# Welcome

Monitor, analyze, and export data about power markets. Grid Status has all the tools you need to stay on top of what's happening on the grid.

<figure><img src="/files/U91uy4SY4WfEr1L59zYB" alt=""><figcaption></figcaption></figure>

Our mission is to provide accessible, actionable energy data to accelerate the energy transition. The documentation here will give you everything you need to know to be successful with our platform.

For additional support or questions, please [Contact Us](https://www.gridstatus.io/contact).

### Other Resources

<table data-view="cards"><thead><tr><th></th><th></th><th data-hidden data-card-cover data-type="files"></th><th data-hidden></th><th data-hidden data-card-target data-type="content-ref"></th></tr></thead><tbody><tr><td><strong>Grid Status Website</strong></td><td>Open and use our product</td><td><a href="/files/ISg5mejdSFyM6WSjWWV9">/files/ISg5mejdSFyM6WSjWWV9</a></td><td></td><td><a href="https://www.gridstatus.io/">https://www.gridstatus.io/</a></td></tr><tr><td><strong>Python Client Library</strong></td><td>Python client for accessing the GridStatus.io Hosted API.</td><td><a href="/files/1Zreg7aaBq2nIQTPZpHg">/files/1Zreg7aaBq2nIQTPZpHg</a></td><td></td><td><a href="https://github.com/gridstatus/gridstatusio">https://github.com/gridstatus/gridstatusio</a></td></tr><tr><td><strong>Grid Status Exports</strong></td><td>Blog where we share our thoughts and analysis on the ever-evolving electrical grid.</td><td><a href="/files/BiZOLg6pF4h2lWsnRHSo">/files/BiZOLg6pF4h2lWsnRHSo</a></td><td></td><td><a href="https://blog.gridstatus.io/">https://blog.gridstatus.io/</a></td></tr></tbody></table>


# Quickstart

Customize the Grid Status platform to monitor the energy markets and access real-time and historical datasets with ease.

1. **Create an API Key:** Navigate to Settings and the API page to Create Your API Key. Once created, browse the data catalog for datasets applicable to your ISO and energy insights.

{% content-ref url="/pages/wLbS8bH4S903ESYAUPUl" %}
[Getting Started](/grid-status-api/getting-started)
{% endcontent-ref %}

2. **Create an Alert:** Choose a data series and set alert. Examples include curtailment volume.

{% content-ref url="/pages/MVkYeH85yz0RPYP6GCEU" %}
[Alerts](/monitor/alerts)
{% endcontent-ref %}

3. **Create a Dashboard:** Navigate to Dashboards and select data series to visualize trends in energy markets.

{% content-ref url="/pages/bXH2MCXakMtlf2smVsxB" %}
[Broken mention](broken://pages/bXH2MCXakMtlf2smVsxB)
{% endcontent-ref %}

4. **Find a Dataset:** Browse the Data Catalog and preview datasets for your energy insights.

{% content-ref url="/pages/8dkdp954PYaCp7R9Sf30" %}
[Data Catalog](/data/data-catalog)
{% endcontent-ref %}

5. **Create an Export:** Choose a data series and download a curated selection by choosing specific columns and dates.

{% content-ref url="/pages/x1e9YvkpOE8QwND8Pl5t" %}
[Data Exporter](/data/data-exporter)
{% endcontent-ref %}

{% hint style="info" %}
Find time [here](https://cal.com/team/grid-status/discovery-call) to schedule a walkthrough and explore subscription plans.
{% endhint %}


# User Guide

Common tips and tricks for how to set up and use Grid Status.

Here are some of the things you will to set up or learn to help get the most value out of Grid Status.&#x20;

## General

Keyboard shortcuts are available anywhere in the application.&#x20;

| Shortcut            | Action           |
| ------------------- | ---------------- |
| `Cmd-K` or `Ctrl-K` | Search Spotlight |

## View Subscription Usage

Navigate to **Settings** and the *Usage* page to view subscription limits and current monthly and daily usage. Each plan has specified limits for monthly usage and API rate limits.

<figure><img src="/files/RfZHk3vegLWSlfR3BKB5" alt=""><figcaption></figcaption></figure>

## Dark Mode

Select dark or light mode from *Theme* in **Settings**.&#x20;

<figure><img src="/files/Qj3eqh3EtAdKebS38NBP" alt=""><figcaption></figcaption></figure>

## Change Primary Email Address

Log into your Grid Status account and go to **Settings**.&#x20;

1. Locate the *Account* page and *Profile* information
2. Select *Add email address* to add an additional email
3. Input verification code to confirm email address
4. Set email as Primary

<figure><img src="/files/P9HO1fJ3ScrOL1pQKUJc" alt=""><figcaption></figcaption></figure>

## Grid Status Updates &#x20;

Grid Status’s constantly improving platform is built to scale to our quickly growing customer base and seamlessly serves the needs of Fortune 100 companies as well as single-employee consulting practices. Email in feedback, dataset requests, or schedule time with our team to share your use case for energy data.

To stay up to date, these are our changelogs.

* [Dataset Changelog](https://gridstatus.notion.site/dataset-changelog)
* [Application Changelog](https://docs.gridstatus.io/changelog/)


# Organizations

How to send invitations, set roles, and manage profiles.

## Creating An Organization

Organizations are set up as part of Grid Status onboarding. Reach out to <contact@gridstatus.io> to learn more about subscription plans available for teams.

{% hint style="info" %}
If your plan includes **Single Sign-On (SSO)**, please contact us to set it up. This feature is for teams that manage user accounts through an identity provider (IdP). We support Microsoft Azure AD, Google Workspace, Okta, and any other SAML-compliant IdP.
{% endhint %}

## Select Organization Account

If you are already a member of an organization, you can switch to that account by selecting it from the Account Menu in the sidebar. An organization subscription allows you to access shared data and share resources across teams.&#x20;

<figure><img src="/files/vYjb4qCUpub1dF5ro9Iu" alt="" width="375"><figcaption><p>Select a personal account or available organization from the menu.</p></figcaption></figure>

## Organization Roles

**Admin**: Users can send invitations to other users, set roles to either Admin or Member, and manage the available licenses for an organization.

**Member**: Users can view other members of their organization and be invited to team dashboards, subscribe to alerts, and access the organization's subscription plan.

## Manage Organization Members

Navigate to your **Settings** and select the **Organization Members** page where you can invite team members and manage user licenses.

You can view seats available by checking the number of organization members.&#x20;

<figure><img src="/files/kwz2Jrq5oV6BSmjnWQ1v" alt=""><figcaption><p>Invitations tab on the Organization Members page.</p></figcaption></figure>

## Send Organization Invites

Input the user's email address to invite them to the organization. Once the user has joined the organization, Admin users can set the role for users to either an *Admin* or *Member*.

To join the organization, new Grid Status users can:

1. Follow the email instructions and be directed to create a Grid Status account to join their organization.
2. Use the specified email address to create a Grid Status account and select the organization from the Account Menu upon logging in.

If the user has an existing Grid Status account, use the associated email to log in and select the organization's account to access the subscription plan.

## Verified Domains

To add a verified domain, Admin users can manage this from **Organization Settings**. Domains are verified with a code sent to an email with the associated domain in order to verify that it belongs to the organization.&#x20;

<figure><img src="/files/UDpX4nHGiK9ki7u90Vjd" alt=""><figcaption></figcaption></figure>

Once verified, Admin users can set emails with a verified domain to either:

* Allow the user to automatically join the organization when they log in
* Allow the user to view the organization and submit a request to join the organization

<figure><img src="/files/iSwVcCqmLdQWcZZPWNcb" alt="" width="375"><figcaption></figcaption></figure>

## Manage Account Preferences

Visit [*Preferences*](https://www.gridstatus.io/settings/preferences) in Settings to manage your personal account if you are user with a personal account and belong to an organization. You can view and access your personal account by toggling the settings pictured below.

<figure><img src="/files/T3NGIlVMPiQyGT4H4mGD" alt=""><figcaption></figcaption></figure>


# Grid Status Labs

Early access to experimental tools and features that are actively being developed and tested.

Labs features allow users to explore new functionality before official release and provide feedback that helps shape future improvements.

### How Grid Status Labs Works

<figure><img src="/files/YIB2VmCQd3RalXZujkOo" alt=""><figcaption><p>Grid Status Labs badge for the Nodal Analysis Application.</p></figcaption></figure>

When a feature is part of Grid Status Labs, it will display an Early Access badge within the application. This indicates the feature is still under development and may evolve based on user feedback.

Labs features are functional and usable, but may undergo design, performance, or capability updates over time.

### How to Access Labs

<figure><img src="/files/454G5SHtiAFA65FqAzwK" alt=""><figcaption><p>Account Settings page to view and select from Grid Status Lab products.</p></figcaption></figure>

To enable Grid Status Labs:

1. Navigate to your [Account Settings](https://www.gridstatus.io/settings/labs)&#x20;
2. Select the **Labs** tab
3. Toggle on the features you would like to access

Once enabled, you can access applications. Features will display an Early Access badge.&#x20;

{% hint style="info" %}
Your feedback helps improve features under development. If you have suggestions, encounter issues, or would like to request additional functionality, reach out to <support@gridstatus.io>.&#x20;
{% endhint %}


# Grid Status Live

Your portal to what's happening in wholesale energy markets.

Our Live pages are the entrance to the entire app. Here you'll find an overview of all markets as well as market-specific information, all with shared functionality to make exploring grid conditions easy.

### Everywhere

On the Everywhere page you'll get an overview of all markets. This page contains data and charts that are available in every market. It's not specialized to any of their individual qualities. At the top of the page you can flip between markets, but for now let's focus on the content of [gridstatus.io/live](https://www.gridstatus.io/live).

<figure><img src="/files/SWGaL0SNUB6g9dZAmoOW" alt=""><figcaption><p>Everywhere Live page.</p></figcaption></figure>

There are two tab structures on the page. First, below the table and map are buttons for Prices, Fuel Mix, Load, and Renewables. Each of these flips to a new section of graphs with the relevant information for each market.

Between this section and the top row is a banner. We update these frequently, so look out for links to new blogs and public dashboards.&#x20;

Clicking on any row of the table to the left of the map will take you to that respective market's live page, and you can also open the map directly from the "Open" text in the upper right.

### Market Live Pages

Each market has its own live page. Here you can still flip between markets using the buttons at the top of the page, but a date selector is also available. Once you change dates on any market page, that selection will hold as you flip through markets.

<figure><img src="/files/5mtusCfnuLjPpo8F228W" alt=""><figcaption><p>ERCOT Live page</p></figcaption></figure>

Each live market page starts with the same building blocks, but expands into additional figures with market-specific data elements. This includes battery operations in ERCOT and CAISO, curtailment in SPP, zonal load in PJM, and more!

On every graph you can click on individual legend elements to turn them on or off. If you want more information on a particular dataset in a graph you can select "More Info" after clicking the download button in the upper right of a chart. Now let's take a brief look at the three tabs for each ISO/RTO.

<figure><img src="/files/Gsf2iP79OYJzNjMy2LBx" alt=""><figcaption><p>ERCOT Live Page featuring the RTC+B pre-built Dashboard.</p></figcaption></figure>

<figure><img src="/files/jFwtc4p1UX9HmyRZ4XwC" alt=""><figcaption><p>IESO Live Page with the Generators view for Solar units.</p></figcaption></figure>

### Conditions

Grid Conditions is the default tab. Here you'll see load, price, fuel mix, and some of those individual-market elements mentioned above.

<figure><img src="/files/vgoPTf0CGRfyQELS2Aoi" alt=""><figcaption><p>PJM Conditions and pre-built cards for load, renewables, area control error (ACE).</p></figcaption></figure>

### Pricing

Pricing contains a curated selection of points, nodes, or aggregates for each market. Typically we include the major Hubs and Zones as well as a selection of other interesting points, such as external interfaces.

<figure><img src="/files/vfvbam8zBXWc2tsXwE2D" alt=""><figcaption></figcaption></figure>

Sync your cursor using the toggle in the upper right to compare prices across points at the same time.&#x20;

### Trends

Finally, we have the Trends tab. This tab has a selection of rolling averages and recent historical review of market conditions and outcomes. Use it to get a quick view of the market's disposition in terms of load and fuel mix over the last month.

<figure><img src="/files/Sd7Swfq27aTms7xKQgHm" alt=""><figcaption></figcaption></figure>

### Pre-Built ISO Dashboards

#### ERCOT Live Page: RTC+B

The ERCOT Live page provides market-wide visibility into pricing, load, fuel mix, and ancillary services activity. In addition to the standard Grid Conditions, Pricing, and Trends tabs, ERCOT includes a dedicated [RTC+B tab](https://www.gridstatus.io/live/ercot#rtc_b) for monitoring ancillary service markets.

<figure><img src="/files/rMOKj0PlBs0sbNsXZmA2" alt=""><figcaption><p>ERCOT Live Page featuring the RTC+B Dashboard.</p></figcaption></figure>

The RTC+B dashboard features:

* Real-Time Clearing Prices for Capacity by SCED interval (Reg-Up, Reg-Down, RRS, Non-Spin, ECRS)
* Real-Time Clearing Prices for Capacity by 15-minute interval (Reg-Up, Reg-Down, RRS, Non-Spin, ECRS)
* Day-Ahead Clearing Prices for Capacity
* DAM Total Ancillary Services Sold

These charts are also available as prebuilt components within the Charts & Dashboards application under ERCOT.

#### IESO Live Page: Generators

The IESO Live page includes a [Generators tab](https://www.gridstatus.io/live/ieso#generators) that provides review of the real-time and historical generation of power plants and their constituent units in Ontario. The Generators dashboard displays unit-level generator output to understand unit behavior by plant and fuel type.&#x20;

The aggregate view of all units allows users to scan and compare units. Users can also identify which plants are ramping, tripping, or responding to changing system conditions. Wind and solar units display actual and forecast output. Dispatchable resources display actual generation and available capability.

<figure><img src="/files/IpeXIVsp1CznU99o4Lv3" alt=""><figcaption><p>IESO Live Page with the Generators view for Solar units.</p></figcaption></figure>

The Generators tab features:

* A multi-select filter to view one or more fuel types
* A group units toggle to aggregate units by plant
* A sync tooltips toggle to compare units at the same timestamp
* A date selector for historical analysis

#### CAISO Live Page: EDAM

The CAISO Live page features a dedicated [EDAM tab](https://www.gridstatus.io/live/caiso#edam) for monitoring the Extended Day-Ahead Market. View pricing, load, and solar and wind data from the pre-built dashboard.&#x20;

If you need help analyzing the dashboard, check our blog, [Western Markets Expansion Part 3](https://blog.gridstatus.io/the-starting-line-of-edam/), where we go over Day-Ahead clears, interchange data, GHG pricing, and more.

<figure><img src="/files/uQr5dy3jc7PsizLpKuIJ" alt=""><figcaption></figcaption></figure>

The EDAM tab features:

* Price cards showing day-ahead clear and real-time values for PACE and PACW hubs
* LMP graph showing day-ahead clear and real-time values for PACE and PACW hubs
* Load and day-ahead forecast
* Wind and solar (renewables) graph
* PACE ↔ SPP West Interchange


# Insights Feed

A live feed of analyst commentary, touching all aspects of the energy space from short term analysis and trends, fuel commentary, and wider developments.

Grid Status Insights keeps you informed and shares analytics on evolving market conditions. Posts are featured in chronological order and cover a variety of subjects, including seasonality, extreme weather impacts, real-time market dynamics, and operational shifts across different ISOs.&#x20;

## Insight Posts

Each post is authored by our own Grid Status Markets team who share their expert observations and data-driven analytics.&#x20;

The search feature surfaces Insights along with topics based on what is available in the archive. Sort results by relevance or filtering by the newest results. You can also refine results using author, market, and topic filters. Highlight any term within a post to launch a search directly, or use the site-wide spotlight search to find Insights content from anywhere.

<figure><img src="/files/E4tHyyKvXntkrfnmlr6U" alt=""><figcaption><p>Homepage for Grid Status Insights with search function opened.</p></figcaption></figure>

To navigate and interact with posts, use the following tools:

* **Author Profile:** View all posts by a specific Grid Status individual and learn more about their areas of expertise. Each profile highlights their insights and provides a brief bio.
* **Markets Filter**: Narrow down posts by ISO/RTO to focus on the regions most relevant to you.
* **Recent Topics:** Select one or more tags (e.g., Congestion, Large Loads, Winter) to view insights tied to specific themes.
* **Save Feature**: Bookmark posts to revisit later from the Saved tab on the homepage.
* **Share Link:** Copy a direct link to any insight for easy reference.
* **React Buttons**: Like or dislike a post to tailor future insights to your interests.

The search feature surfaces Insights along with topics based on what is available in the archive. Sort results by relevance or filtering by the newest results. You can also refine results using author, market, and topic filters. Highlight any term within a post to launch a search directly, or use the site-wide spotlight search to find Insights content from anywhere.

<figure><img src="/files/UiJJbRknqlTlaYrs7ouj" alt=""><figcaption><p>Highlight text to search all insights related to "negative congestion".</p></figcaption></figure>

## Topic Pages

<figure><img src="/files/8c0Gyv0kpZwZEueqPT4S" alt=""><figcaption><p>Western Interconnection topic page for Grid Status Insights.</p></figcaption></figure>

Topic pages provide a dedicated view for themes mentioned in the Insights Feed. Each topic page includes:

* A brief topic description
* A list of related topics
* A chronological view of all insight posts tagged with that topic

To browse topic pages, select a topic from the Recent Topics menu on the Insights Feed homepage or input a topic into the Insights search bar.

## Market Advisory Services

{% hint style="info" %}
Interested in a Market Advisory Services? Calls and email support are included in Enterprise subscriptions and you can learn more by reaching out to our sales team at <contact@gridstatus.io>.&#x20;
{% endhint %}

<figure><img src="/files/v2JdAUrpaUZyxUy9LYRI" alt=""><figcaption><p>Direct link to an insight authored by Tim Ennis and view for the market advisory scheduling link.</p></figcaption></figure>

Our advisory calls are on-demand sessions with our Markets team.

The team draws on their experience as market monitors and industry analysts to share practical insights tailored to your operations, along with strategic guidance on how to navigate the energy markets.

Session topics are scoped out prior so we can provide personalized analysis and detailed coverage.

**Example Topics**

* Asset-level DART optimization and basis management
* Transmission and generation-driven congestion risks
* Personalized conversations on any post in Grid Status Insights
* Load, weather, and renewables impact on market outcomes
* Interconnection queue signals for future congestion


# Map Application

Grid Status maps provide interactive visualizations of wholesale electricity markets and grid infrastructure.

### Map Application Overview

Use the Grid Status Map Application to explore locational marginal prices (LMPs), generation facilities, infrastructure, and balancing authorities. These tools help you understand how electricity is generated, priced, and transmitted across energy markets.

Use the **Map Menu** in the upper-left corner to switch between the following views:

* **Nodal Price Map**: Displays real-time and historical LMPs across the grid. Users can view total LMP or individual components (Energy, Congestion, and Losses). Note, locations and relationships are inferred from public sources. Not all system buses are visualized, and market coverage varies by ISO.
* **Power Plant Map:** Shows currently operational facilities across the U.S., color-coded by primary technology type (e.g., solar, wind, gas) and scaled by capacity.
* **Balancing Authorities:** Outlines the regions managed by each Balancing Authority (BA) in the U.S. This map provides a high-level view of operational boundaries and provides links to pre-built dashboards per region.
* **Grid Infrastructure**: This map displays the high-voltage grid infrastructure for the U.S. bulk power system. The map layer covers transmission lines and substations.

<figure><img src="/files/LPj8G6DRQWsQXcXVe5Sn" alt=""><figcaption><p>Nodal Price Map set to view Real-Time LMP prices and Price Nodes.</p></figcaption></figure>

### Nodal Price Map

Nodal locational marginal prices (LMPs) are the backbone of wholesale electricity system optimization and power plant dispatch in power markets. These prices include the cost of energy, transmission losses, and congestion.&#x20;

#### **Customize the Nodal Price Map**

To customize the Nodal Price Map for your own analysis, you can adjust the following settings:

* &#x20;**ISO Filter:** Filter nodes by ISO/RTO. The multi-select option allows viewing more than one ISO and monitoring cross-border price dynamics.
* **Time Slider & Date Selector:** Explore historical pricing data by selecting specific dates and times.
* **Pricing Data** **Menu:** Select **Real-Time**, **Day-Ahead**, or **DART Spread** prices using the menu and the **LMP component** (energy, congestion, or loss) to adjust node color.
* **Search Bar:** Quickly find and zoom to a specific node by typing its name.
* **Layer Menu:** Switch between a stylized map view for clarity or a satellite view for geographic context. Overlay grid data with weather radar data and view current conditions affecting operations.
* **Legend Color Scale:** Choose between a fixed or dynamic scale to control how node prices are visualized. The dynamic scale adjusts to current data for better visibility of variation within an interval, while the fixed scale enables easier comparison across time.
* **Display Mode:** Choose either Nodes or Hex view. Hex view aggregates nearby nodes into hexagons colored by mean price. Useful for spotting regional patterns when individual nodes are too dense.

#### Nodal Prices & Coordinates

<figure><img src="/files/Mhx5o2Osx9LNnuRugWYC" alt=""><figcaption><p>CIN.TIPMONT Node with pricing chart and data table view opened.</p></figcaption></figure>

* **Pricing Chart Preview:** When a node is clicked, the bottom panel provides real-time and day-ahead pricing data for the selected node. Open the node’s full analytics page in the Nodal Analysis Application using the location button.
* **Data Table:** Open the data table to view pricing components per node. You can search and filter for in view pricing nodes using the toggle.
* **Nodal Coordinates:** Users with a Grid Status Enterprise subscription can export the full list of price node locations directly from the Nodal Price Map. The export option is located in the Map Layers settings panel under **Price Nodes**.

<figure><img src="/files/6UPkqDtnidSUtByBrsRU" alt="" width="563"><figcaption><p>Export Button for Price Node Geo Data and filter the export to include nodes without pricing data.</p></figcaption></figure>

### Power Plant Map

<figure><img src="/files/GjoudC06pqVOcYGYMTSC" alt=""><figcaption><p>Roseton Generating Facility and generation data. </p></figcaption></figure>

The Power Plant layer visualizes generation facilities across the U.S. Enable this layer from the Map Layers menu and zoom in to see assets near pricing nodes. Hovering over a power plant displays key facility details, including the plant name, owner, primary technology, number of units, and total capacity.

**Map  Filters and Customization**

Power plants are displayed using color-coded markers based on their primary technology type (such as solar, wind, or gas). Marker size scales by plant capacity, making larger facilities easier to identify at a glance.

You can further refine the view by size, capacity, and growth curve. These controls make it easier to focus on relevant asset classes, reduce visual noise, and perform spatial analysis when evaluating congestion, pricing risk, or project siting near key grid infrastructure.

**Generation History**

Click a power plant when the power plant layer is available and view a stacked monthly bar graph of the plant's output. The stack is by fuel type and uses gross generation for the y-axis value.

To view the dataset, you can check out [EIA Power Plant Operations](https://www.gridstatus.io/datasets/eia_power_plant_operations) dataset.

### Grid Infrastructure Map

<figure><img src="/files/BZlfCBXI08Qm08fiJhqO" alt=""><figcaption><p>View of Don Marquis Substation on the Grid Infrastructure map.</p></figcaption></figure>

The map can viewed either as a Nodal Price Map layer or a standalone map. This map layer is tied to the **transmission lines** and **substations**. Double-click to zoom on that substation and the geographic area. Clicking on a transmission line will automatically bring the line and other selected map information into focus for you to view what is in proximity of the line.

The line name, voltage, operator, and type will appear when you hover over a specific transmission line. To locate the grid asset, use the following methods:

* Keyword search for Transmission Line/Substation
* Voltage Class


# Interconnection Queue

The Interconnection Queue Application provides tools to analyze project pipelines, track development milestones, and monitor how generation capacity is evolving across regions.

## Interconnection Queue Overview

<figure><img src="/files/J90QYYPnlG0JInSp3eJF" alt=""><figcaption><p>Homepage for the Interconnection Queue Application.</p></figcaption></figure>

#### How to Search and Filter for Projects

The Interconnection Queue Application provides an interactive database of interconnection projects across major ISOs. Users can browse the full queue or refine results using filters to identify projects by region, technology, or development stage.

Projects are displayed in a table with key information including project name, queue ID, capacity, technology type, status, projected commercial operation date (COD), and fuel.

* **Search Bar:** Use the search bar in the upper-right corner to find projects by name. This searches across all indexed project names in the database.
* **ISO Filter:** Limit results to a specific ISO or RTO (e.g., ERCOT, PJM, CAISO) to focus your search on a particular market.
* **Fuel Filter**: Filter projects by generation fuel type, such as solar, wind, battery storage, or other technologies.
* **Technology Filter**: Refine results by technology classification used in the interconnection filings.
* **State Filter:** Limit results to projects located within specific U.S. states.
* **Status Filter**: View projects by interconnection stage, such as: Queue Position, Study Phase, Interconnection Agreement Executed, In Service, or Withdrawn.
* **Capacity Range:** Set minimum and maximum capacity ranges (MW) to isolate projects of interest.
* **Actual/Projected COD Range:** Filter projects by actual or expected Commercial Operation Date to identify upcoming generation additions.

## Project Page Overview

Selecting a project from the main queue table opens a detailed project page. This page provides deeper insight into the project’s development status, milestones, and historical updates.

<figure><img src="/files/svdmpkZ5e2J8rofchzVd" alt=""><figcaption><p>Hawthorn Solar project view.</p></figcaption></figure>


# ERCOT 4CP Monitor

Analyze ERCOT’s Coincident Peak Load and use real-time insights to identify and respond to potential 4CP events.

{% hint style="info" %}
The ERCOT 4CP Monitor is available only for paid Grid Status subscriptions. Reach out to <support@gridstatus.io> to learn more.
{% endhint %}

<figure><img src="/files/9gAWzoNrRexo6UNbqUQ1" alt=""><figcaption><p>ERCOT 4CP Monitor and risk outlook for week of June 10th.</p></figcaption></figure>

### Heads Up Display

The heads-up display provides a breakdown of the latest 15-minute interval and indicates if the values have increased or decreased. The display shares real-time values, the data refresh frequency, and a *Refresh* button to update and view the estimated CP load as it accumulates.

The **Partial Interval** toggle enables real-time monitoring of the current, incomplete 15-minute interval. When turned on, it highlights incomplete intervals in tables and bar charts. This partial interval view helps you respond faster during peak-risk periods.

**Listed Real-Time Values:**&#x20;

* Estimated CP Load
* Month-to-date (MTD) Peak
* Difference from MTD Peak

### 4CP Risk Outlook

The risk outlook features a seven-day view of peak risk and assigns values for risk estimates based on real-time ERCOT data. Each day's risk score (0–10) estimates how likely that day is to set the monthly peak — the 15-minute interval that drives ERCOT's 4CP transmission charges.&#x20;

Navigate to the ERCOT 4CP Monitor to read more about the score formula and how the reference peak is computed.

<figure><img src="/files/uzLtHsEEiTVHAqKMRHAK" alt=""><figcaption><p>4CP Risk Outlook for week of June 18th.</p></figcaption></figure>

### **Forecast Evolution** **Trends**

Forecasts are updated on a 5-minute interval to surface shifts in expected conditions. The graph tracks the system load over the last seven days and uses the latest forecast vintage to calculate whether the system load is trending up or down.

<figure><img src="/files/FfOqq7spPno0VeNfV3KV" alt="" width="563"><figcaption><p>Forecast evolution for July 30, 2026 featuring a trending increase.</p></figcaption></figure>

### Month-To-Date Rankings

The 4CP Monitor tracks current monthly peak across the following graphs:

<figure><img src="/files/0IpPNIxynkpOZTzDYgTA" alt=""><figcaption></figcaption></figure>

* **Daily Peak Window:** The current day graph zooms in on the peak period to show the latest forecast, Day-Ahead Bid Close Forecast, MTD peak, and, during the window, the Estimated CP Load. You can also flip back to any previous day for a look at demand behavior and outcomes over the peak.
* **7-Day Forecast Outlook**: The forecast outlook tracks ERCOT's load forecasts for today and the next six days alongside the current month-to-date peak. Each day displays its forecasted daily peak, so you can see at a glance which upcoming days are projected to approach or exceed the MTD peak.
* **Est. CP Load by Interval:** This bar chart tracks estimated CP load for each 15-minute interval, with the MTD Peak marked as a reference line so you can see how close current load is running to the month's high. Hover over any bar to view the interval's exact start time and load value. Use the time range selector to adjust the window, or download the underlying data with the export button.
* **Estimated CP Load Profiles (Month to Date):** The chart overlays each day of the current month as a full 24-hour curve. Today's profile is highlighted in green and the maximum profile in red, with prior days shown in gray. The graph monitors whether today's demand is shaping up above or below the month's peak day.

### Coincident Peak Tables

<figure><img src="/files/buuw6jY5kqymjJRHE8OL" alt=""><figcaption></figcaption></figure>

* **Coincident Peak Rankings Table**: This table ranks month-to-date intervals by their CP load. It provides key data to support operational strategy and risk planning for the rest of the month. This table is intended to offer directional insight into how intervals rank to help you evaluate potential CP risk more effectively.
* **Interval Data**: This table displays the interval status and provides key data to identify upcoming and completed intervals.&#x20;


# Alerts

Develop your own notifications feed.

With Alerts you can get email and SMS notifications when any data series hits a particular threshold. Use Alerts to monitor prices, track load, understand when certain fuels cycle, and more.

### Alerts Homepage

On the Alerts homepage, you can manage alerts by deleting them or creating new ones. You can also see who created the alert as well as time of creation and last update.

<figure><img src="/files/xsWwYxoYZHWi3XoK5eWI" alt=""><figcaption></figcaption></figure>

### Alert Configuration

To configure an alert, select the dataset and value for when you want to be notified.&#x20;

Choose a name for your alert, then, below, you can search for a specific series. Once you've selected a dataset you'll be prompted to pick the column you want to set the alert on. The options to the right of series selection allow a choice of operation as well as the value. One thing to confirm is that the value you enter makes sense in the context of the selected data series. In some places on the site we may show load in GWs, but the underlying data is in MWs. If you wanted to track ERCOT loads about 80 GW, the value you'd set is 80,000.

For notification method, users can select email, SMS message, or both.

<figure><img src="/files/YAMlJbQ0icMLhNeBrU1r" alt=""><figcaption></figcaption></figure>

Notification Timeout prevents a series of notifications after the initial one for a set amount of time. If set to 0, you won't be alerted to the same data point twice (the alerts system runs on a quicker frequency than nearly all data). There won't be a timeout on new notifications if the next value(s) in a series continue to trigger an alert.

### Example Email

The emailed alerts contain the alert name, time, condition, and value. You can also click the button to see the alert in the App.

<figure><img src="/files/I5VCxWxk8LcW2opVL4qS" alt=""><figcaption></figcaption></figure>

Make sure your email client has whitelisted emails from the gridstatus.io domain to ensure they reach your inbox successfully.

### SMS Example

The text message alerts contact the alert name, time, condition, and value.&#x20;

<figure><img src="/files/s3aUIeyKcbdjBMUEuYL3" alt="" width="375"><figcaption></figcaption></figure>

### Alert History

At the bottom of the Alert page, users can view a history of notifications.&#x20;

<figure><img src="/files/8tmoc9YTR91pf7ACAGOa" alt=""><figcaption></figcaption></figure>


# EIA Browser

An application to explore EIA data and monitor grid events.

While RTO/ISO markets cover much of the country, several regions have limited data access due to the lack of an overarching operator and open market structure. The intermountain west and southeast in particular can seem opaque to outside observers. We built this application, in part, to help provide more visibility into energy across the entire country. It relies on EIA data reported by balancing authorities on an hourly basis. Unfortunately, this data is more prone to incorrect outliers and data drops than direct ISO/RTO feeds, so we recommend using data directly from an ISO/RTO when possible.

### Main Page

<figure><img src="/files/mcUUlvjs1u36KLAZhj19" alt=""><figcaption></figcaption></figure>

The main page presents a comprehensive list of Balancing Authorities and EIA-defined regions. Quickly find your region by using the search bar or by scrolling through the list.

### Balancing Authority Pages

These dedicated pages offer a familiar experience, mirroring other Live dashboards on gridstatus.io. We've curated essential metrics from EIA data to provide a clear overview for each Balancing Authority. You can customize the date range and time zone, and sync your cursor across multiple charts for detailed analysis.

<figure><img src="/files/W0PycxjQpyoKGtuFfV4M" alt=""><figcaption><p>Chart (Above) displays Fuel Mix, Chart (Below) displays Load, Load Forecast, Net Generation. Note that fuel mix components vary by market.</p></figcaption></figure>

<figure><img src="/files/3kvTQN0BbcasaiLil8tt" alt=""><figcaption><p>Chart (Above) displays interchange, Chart (Below) displays emissions intensity for both generation and consumption.</p></figcaption></figure>

### Balancing Authorities Map

Use our interactive map to find a balancing authority geographically. From the map, click on any BA and it will direct you to its dedicated page. ISO/RTOs regions are an exception; clicking these areas will take you to their respective [gridstatus.io/live](https://www.gridstatus.io/live) page.

Toggle to view peak load and assist with the overlapping nature of balancing authorities on a geographic map; topography does not equal topology in practice.&#x20;

<figure><img src="/files/e809kVklGpHn5K3ZY92A" alt=""><figcaption></figcaption></figure>


# Record Tracker

Tracking record-breaking moments in real time.

We calculate records for a variety of metrics across each ISO/RTO. Some of these are unique to a particular market depending on their resource mix and the availability of data. This data is also available via the API.

{% hint style="info" %}
Records are based on real-time data available in Grid Status from each ISO. Certain records, like load, may have corrections after the fact as markets add back in demand that is not present in the raw load data feeds.
{% endhint %}

### All Records Timeline

This is the front door for the records tracker. Here you see a timeline of records as they are set. Clicking on the markets takes you to their records page, and clicking on an individual record takes you to the page for that record in the specific market.

<figure><img src="/files/UMT80aZpVCDLP8kVGtVv" alt=""><figcaption></figcaption></figure>

### Market Records

The Market Records page shows a card for each record as well as a filtered version of the All Records Timeline, just for the selected market. You can click through to the specific records either from the cards or the View Record button on the individual records.

<figure><img src="/files/36eg2cHHTMevHdj3OKb8" alt=""><figcaption></figcaption></figure>

### Specific Records

Each specific metric and market combination has its own page. At the top you can see the current record as well as the previous record value. Below those cards is a timeline of values for the record. This timeline only shows changes at the top end of the record.&#x20;

Below the chart is the top ten days. While a former number one record can move down the list, a new entry below the #1 spot does not show up on the chart.

<figure><img src="/files/lY09Qj1d2G0KChXoYXX1" alt=""><figcaption></figcaption></figure>

### View Day

If you click "View Day" in the row of any individual record or top ten entry you will be taken to the Live Page for that market set to the day. You can use this feature to quickly assess other conditions on the grid at the time. A record wind or solar day in ERCOT may not just be well-suited from the weather, it also likely requires a balance of load and generation that doesn't bottle up those resources in the South or West leading to congestion and curtailment. By reviewing a record day you may be able to uncover some of these trends for yourself.&#x20;

<figure><img src="/files/s3B8GTIzThLCkdME99dy" alt=""><figcaption></figcaption></figure>


# Trends

Cumulative grid metrics that track market movements based on ISO, period, and current stats.

<figure><img src="/files/gRBD8NBt7WTktwYvJye9" alt=""><figcaption><p>ERCOT supply and demand trends for the month of August 2026.</p></figcaption></figure>

The Trend Analysis application tracks cumulative generation by fuel type across ISOs. Compare how the current period is tracking against previous periods. To view ISO-specific markets, navigate the top menu and move between ISO views.&#x20;

#### Charts

With the charts, view generation type and it's output and how it tracks against a selected period of time. You can draw insights to identify long term shifts. Hover over any point on the chart to view cumulative values at that timestamp and the percentage difference between the current period and historical periods.

<figure><img src="/files/YzZAEmOltJMRCvbGw8YX" alt="" width="563"><figcaption></figcaption></figure>

#### Data Coverage

Click a metric to open the stats behind the chart. This shows the data source's frequency, expected, actual, missing, and interpolated values. Raw coverage reports the share of intervals for which data is received. This view tracks how much of the cumulative total is based on reported versus interpolated data.

<figure><img src="/files/Z5ZxMCKlpR8FW2NeFPIx" alt="" width="518"><figcaption><p>Data coverage table for ERCOT Wind generation.</p></figcaption></figure>


# 1.0 ERCOT 4CP Monitor

Analyze ERCOT’s Coincident Peak Load and use real-time insights to identify and respond to potential 4CP events.

{% hint style="info" %}
Note: ERCOT 4CP Monitor application is available only for paid Grid Status subscriptions.&#x20;
{% endhint %}

## Heads Up Display

<figure><img src="/files/4fsY6mlFt0eIljmKkAZF" alt=""><figcaption><p>Displays current 4CP Monitor values, data refresh frequency, a button to request a dashboard refresh, and a time interval menu to review historical data.</p></figcaption></figure>

The heads-up display provides a breakdown of the latest 15-minute interval and if the values have increased or decreased. See where real-time estimated CP load sits relative to the peak, so you can take action if it crosses your threshold.

<figure><img src="/files/Eu6EZBfyV63rv2emjk5q" alt="" width="563"><figcaption><p>ERCOT 4CP Monitor Application with Partial Intervals view turned on and incomplete intervals highlighted.</p></figcaption></figure>

The **Partial Interval** toggle enables real-time monitoring of the current, incomplete 15-minute interval. When turned on, it highlights incomplete intervals in tables and bar charts. This partial interval view helps you respond faster during peak-risk periods.

Use the *Refresh* button in the upper right corner to update and view the estimated CP load as it accumulates.

## Today’s Data and 7 day outlook

<figure><img src="/files/9zE4vaRTWrUZ9CjshZdV" alt="" width="375"><figcaption></figcaption></figure>

Track real-time estimated CP and system load for today and yesterday alongside ERCOT’s forecasts, giving you a clear view of how load is performing against expectations. You’ll also see the next six days of load forecasts and how they compare to the current month’s estimated CP peak—helping you spot potential risks early.

## Coincident Peak Rankings Table

<figure><img src="/files/TWcSKLkf6J7z59izdiIQ" alt="" width="563"><figcaption></figcaption></figure>

This table ranks month-to-date intervals by their CP load. It provides key data to support operational strategy and risk planning for the rest of the month.

Intra-month rankings are updated as new data becomes available for each interval during the active month. In this table, WSL is equal to the total gross charging from **energy storage resources (ESRs)** during a given interval. This is not the complete calculation for determining coincident peak load, but it is a growing factor with the rise in operational ESR MWs on the ERCOT grid.&#x20;

This table is intended to offer directional insight into how intervals rank—both including and excluding WSL—to help you evaluate potential CP risk more effectively.

## Breakdown

<figure><img src="/files/R7QtB3122j824Qy6UCvR" alt=""><figcaption><p>Change the breakdown time interval using the upper right menu to select your view.</p></figcaption></figure>

The Breakdown section offers a clear, detailed view of each 15-minute interval to help you better understand the factors contributing to Coincident Peak (CP) risk. It includes bar graphs that show three key values for each interval: estimated CP load, total system load, and WSL (gross charging from energy storage resources). These visualizations make it easy to spot patterns and compare how each metric changes over time.

Below the charts, you’ll find a table sorted by timestamp, showing the same interval-level data in a structured, easy-to-read format. This combination of visual and tabular data allows you to analyze trends and track high-risk intervals with greater confidence.

## Trends

<figure><img src="/files/91DbTEk8p6Oa8IX2palT" alt=""><figcaption></figcaption></figure>

The Trends graphs display in real time how key 4CP load components are unfolding compared to previous days. These charts help you quickly assess whether today’s conditions are trending above or below recent Coincident Peak intervals. By comparing current performance against historical patterns, you can better anticipate risk and take action before a new peak is set.

## Load Forecast Evolution

<figure><img src="/files/10CzMBnHOMWSKgMENksP" alt=""><figcaption></figcaption></figure>

The Load Forecast Evolution chart displays how the forecasts change over time, helping you track shifts in load expectations throughout the day and across the week.

All forecast vintages are overlaid, allowing you to:

* See how projected peak hours evolve with real-time data
* Identify upward or downward revisions in load forecasts ahead of potential 4CP intervals
* Gain early insight into when demand may approach or trigger Coincident Peak risk
* View summary statistics such as mean, maximum, and standard deviation

This view is especially helpful for spotting large forecast swings before the actual peak occurs—giving you more time to prepare and act.


# Overview

Create your own view of the grid with custom charts and dashboards to analyze and visualize ISO data.

{% hint style="info" %}
Note: Charts & Dashboards are available only for paid Grid Status subscriptions.&#x20;
{% endhint %}

### Charts & Dashboards Homepage

To access the homepage, click **Charts & Dashboards** from the navigation menu. Here, you’ll see all charts and dashboards available to you—including those you’ve created and those shared with you.

* Use **Charts** to analyze and explore real-time and historical data
* Use **Dashboards** for monitoring data across multiple charts

Use the filter in the upper right to toggle between **All**, **Yours**, and **Shared** items.

<figure><img src="/files/6mNb8JrZTHep0F55Zxoq" alt=""><figcaption><p>Filter menu to view charts and dashboards based on access permissions.</p></figcaption></figure>

### Usage Limits

To view your current usage and plan limits for Charts and Dashboards, go to Settings → [Usage](https://www.gridstatus.io/settings/usage). Charts created within a dashboard do not count toward your individual chart limit—they are independent of standalone charts.

<figure><img src="/files/LL36oOFWvCDY3mPqjYyg" alt=""><figcaption><p>Usage tab to view user and organization limits for charts and dashboards based on your selected Grid Status subscription.</p></figcaption></figure>


# Charts

Use Charts to analyze and explore real-time and historical data.

## Create a New Chart

Navigate to the [Charts & Dashboards](https://www.gridstatus.io/dashboards) application. Click ***+ New Chart*** to get started.

<figure><img src="/files/onJ0KS9M08ZAnyTnI0Mc" alt=""><figcaption><p>Homepage to view Charts &#x26; Dashboards.</p></figcaption></figure>

## Basics for Custom Graphs

To create a custom graph, add any data series listed in the [Data Catalog](https://www.gridstatus.io/datasets).

<figure><img src="/files/NV1oqKe5Il9sNbnrNVAb" alt=""><figcaption><p>Search to add a data series for your custom graph.</p></figcaption></figure>

The Custom Chart Builder is the powerhouse of the chart builder. Here you can take any data series from across the corpus of Grid Status datasets and make your own chart. Let's start with the right panel that takes up most of the screen - adding and displaying data.

The data selection process uses the same search functionality as other parts of the site. If you know enough about the data series you're looking for you can click straight through on the Dataset selection and fill out Series as well. For example, if you want to show ERCOT coal generation and type in *ERCOT coal* it will present options with both the dataset and series selected.

If you don't add a Label the legend entry on the graph will include both the dataset and series name.

To the right are a series of display options for each series:

* **Y Axis**: Changes which y-axis a particular series is plotted against. Helpful when when you want to show data series with different magnitudes of value. For example, frequency needs a tight range to show useful information and you would be unable to usefully plot it with almost any other data on the same axis.
* **Color**: Choose a series color in multiple ways:
  * Type in an HTML color code;
  * Try a pre-selected Grid Status color;
  * Use the color box to alter a selected color, and;
  * Choose the dropper to select a color from anything on screen.
* **Graph:** Choose a graph type from the available options: Line, Bar, or Area.
* **Advanced:** This opens a panel with additional options, not all options are available for all graph types:
  * **Stack Series:** This allows you to stack series on the graph. Every series with this selected will stack. By default, selecting this will change the graph type to area, but that can be changing after selecting to stack a series.
  * **Connect Nulls:** Turned on by default, this will connect null data.
  * **Symbol:** Choose a symbol, and choose whether or not to show it with a toggle to the right.
  * **Stroke Width:** Change the width of a line.
  * **Line Style:** Options such as dashed or dotted for lines.
  * **Line Step:** Whether to show a line step, and if so, where to put it. Options are None, Start, Middle, and End. Useful when looking at hourly data, particularly when comparing it to 5-minute data or resampling to a higher frequency.
* **Duplicate Series:** The two overlapping squares duplicates any data series. Particularly useful when you want to plot multiple series with setups, such as choosing an LMP data set and the congestion component. Duplicating the series means you'll only have to change the location value. Duplication iterates on the color rather than using the same color for each series.
* **Delete:** Deletes a series, does not prompt for certainty, so be careful.

<figure><img src="/files/P7uD8zVLt6x0tJbQU9eL" alt=""><figcaption><p>Example of a multi-series graph and graph settings.</p></figcaption></figure>

## Table Toggle for Charts

<figure><img src="/files/pdFbx9JpNb8KWL7tlzmN" alt=""><figcaption><p>Toggle the graph to be a table using the dropdown menu in a custom dashboard</p></figcaption></figure>

You can toggle any custom graph into a table view using the **component settings** in a custom graph or the **dropdown menu** in a custom dashboard. Mix and match data, sort data by any column, and then transpose the table for your preferred display. To change table view settings, visit the panel for the following options:

* **Pin First Column**: Keep the column fixed and visible while scrolling horizontally across the rest of the data table.
* **Transpose Table**: Flip the data table's rows and columns in order to better compare the data series. This is also known as converting "wide" data to "long" format.
* **Default Sort Column**: Define which column the table is automatically sorted by when it first loads.
* **Default Sort Direction**: Set the initial sorting order applied to the default sort column when a data table first loads.
* **Decimal Digits to Display**: Controls how many numbers appear after the decimal point for numeric values in the table.

<figure><img src="/files/PI2dpFMkTEYk7Rxa6iZ4" alt=""><figcaption><p>Select the icon to switch between a table or chart format.</p></figcaption></figure>

## Formulas & Resampling

Custom Graphs in the Chart Builder also support formulas and resampling of data series. Resampling is a select on the left panel and intertwined with the functionality of custom formulas. In order to do calculations on series they must be at the same frequency. We have you explicitly select a data frequency so that there is no confusion as to what operations are taking place and how.

After you select a resampling option, you'll also see a change to the data series options.

<figure><img src="/files/RxhoSy0VsCLdUPQ8s8Kl" alt=""><figcaption><p>View resample settings for a graph's data series</p></figcaption></figure>

Resample Function allows you to choose how the resampling is carried out. The options are: Mean, Min, Max, Sum, Standard Deviation, and Count. The default function is Mean.

Once you've resampled the data to the same frequency you can add a custom formula. Custom formulas use the alphabet notation to the left of each series. Supported operators include: +, -, \*, /, ^, log, abs, sqrt, and (, ).

One way to use custom formulas is see the difference between renewable forecasts and actuals.

<figure><img src="/files/HbBGS3nQgzBKoI1QsgkF" alt=""><figcaption><p>View for a formula used for a custom graph.</p></figcaption></figure>

## Graph Settings & Reference Marks

To edit the title, hover over the chart name to rename it. If left blank, a title is auto-generated based on the data series selected in the graph.&#x20;

<figure><img src="/files/PBVxcYbwipW4GHuzmxvG" alt=""><figcaption></figcaption></figure>

In the left panel, you can edit the graph settings.&#x20;

* **Show Legend:** Toggle to show the graph legend. The default setting is to turn this on.
* **Enable Zoom and Pan:** Toggle to zoom and pan. The default setting is to turn this off. Zoom and pan is automatically enabled for a graph when it is maximized via the "Full Screen" button in the upper right of every graph when using a dashboard. Turning the option on in the Custom Chart Builder enables this functionality whether a chart is maximized or not.
* **Frequency**: Set resampling frequency. This *Graph Granularity* setting helps standardize and summarize data with varying original frequencies, making it easier to compare and analyze in a single graph.
* **Y-Axis Range:** Set the primary and secondary y axes to match gridlines.&#x20;
* **Reference Marks**: Add an horizontal and vertical annotation lines to the chart to highlight information such as an important threshold or current time

<figure><img src="/files/3yHbw0FYAtxZ15DOM2dC" alt="" width="303"><figcaption></figcaption></figure>

## Manage Charts

Here are the available options for managing your charts:

{% hint style="info" %}
The “Share with Team” feature is only available to organizations with a paid subscription.
{% endhint %}

* **View Charts:** Select the "Charts" tab from the homepage. Use the dropdown menu to filter by public and personal charts. You can also switch between table and card view for browsing the available charts.
* **Share with Team**: Provide access to other users in your organization. This feature is available for paid subscriptions only
* **Duplicate:** Create a copy of the chart and begin editing a duplicate version of an existing chart.
* **Transfer Ownership**: Reassign the chart to another organization listed in the dropdown menu. Organizations listed are ones that you must already belong to.
* **Delete:** Charts added to a dashboard will share a list view of any affected dashboards.
* **Dashboards**: Modify dashboards by either adding or removing the chart from the listed dashboards.

<figure><img src="/files/V6ueRxGATx92xMSC1hjg" alt=""><figcaption><p>Use the top menu above the chart configuration to manage, share, duplicate, transfer ownership, or delete your chart.</p></figcaption></figure>


# Dashboards

Use Dashboards to monitor multiple charts, analyze real-time and historical data, and compare it with external data sources—all in one view.

## New Dashboard

When you click ***+ New Dashboard*****,** you will land on a dashboard with the option ***+ Add Component**.* Read below for descriptions of each option listed in the pictured menu.

<figure><img src="/files/IVbUet3vQZNAuUtryOum" alt="" width="375"><figcaption></figcaption></figure>

To customize your dashboard, you can choose the following options in the upper right corner.&#x20;

* **Edit Layout:** Change the size and shape of components, move the location of components, and delete individual components.
* **Datetime Selector:** Set the datetime range for your components. Tabs provide options for either *Relative* or *Absolute* range&#x73;*. Relative* ranges update based on today's date with options to Lookback or Look Forward. Absolute allows the user to set a specific period of time by selecting dates and adding a time. The Datetime Selector includes a timezone menu as well.
* **Share**: Other users in your organizations can access the charts and dashboards, or a resource, when you select from the menu of roles.
  * Owner: Can view, edit, modify, and delete the resource.
  * Editor: Can view, edit, and modify the resource.
  * Collaborator: Can view and share the resource.
  * Viewer: Can view the resource.
* Additional Options:
  * **Manage Data Sources:** Handle external data sources. This is available only for paid subscriptions.
  * **Duplicate:** Create a copy of the dashboard for customization.
  * **Transfer Ownership:** Designate another user in the organization as the owner.
  * **Delete:** Remove the chart or dashboard.

## Public Dashboards

Public dashboards are available to all users. These dashboards are created by Grid Status and deeper dives into individual markets that exist on the *Live* page. These are a bit more specialized per-market and show off some of the features we'll get to further down the page, like resampling and custom formulas.

View public dashboards by filtering dashboards by *Shared with me*.&#x20;

<figure><img src="/files/6jiK0pquvmDP38h2xQCH" alt=""><figcaption></figcaption></figure>

Public dashboards are market-agnostic and focus on broader trends such as regional hazardous weather or winter risk. Stay on the lookout for more of these as events occur in and around the grid!

<figure><img src="/files/bayUJMkPT72GyUbFd6wt" alt=""><figcaption></figcaption></figure>

These public dashboards show up on the homepage, and we also post them on our social channels when a new one is released. Check out [Bluesky](https://bsky.app/profile/gridstatus.io), [LinkedIn](https://www.linkedin.com/company/grid-status/), or [X](https://x.com/grid_status) to know when new dashboards are available!

<figure><img src="/files/Rda28pNR4cmGygnrihCa" alt=""><figcaption></figcaption></figure>

All Public dashboards can be cloned to your account. Once cloned, you can edit every component to customize the view and get a head start for your own dashboards.

## Prebuilt Components

To simplify setting up your own dashboard, a selection of prebuilt elements are available. These components can be customized by ISO and graph type.

**Saved Chart**: View a list of charts created and add, or remove, them to your dashboard.&#x20;

**Most Recent Value:** Select the dataset and data series. To add to dashboard, set the unit and delta for observed value.

**Historical Profile Graph**: These graphs are also located on *Live Dashboards* on the [*Trends and Profiles*](https://www.gridstatus.io/live/ercot#trends) tab. Customize the graph by selecting the dataset, series, and setting the number of days included in your profile graph. To add granularity, you can add lines for the mean, maximum, and minimum. To view specific historical data, you can highlight data for today, yesterday, or all days.

**Embed Webpage**: Embed other webpages. Note that not every webpage works since it depends on the originating site's permissions. You can view an example by visiting our [Winter Hazards, Outlook, and Operations](https://www.gridstatus.io/dashboards/winter-outlook-operations-2025) dashboard.

**Prebuilt by ISOs:**

Select *+ Add* → *Prebuilt by ISOs* from the upper right corner. From the menu, you can choose:

* LMP
* Fuel Mix
* Load
* Renewables
* ISO's Graph Type (ie. Zonal Load, Outages, Curtailment)

These graphs are the same ones that appear on the ISO Live pages from the Grid Status home page.

**Prebuilt Components:**

Select *+ Add* → *Prebuilt Components* from the upper right corner. From the menu, you can choose:

* ISO Latest Status
* ERCOT 4CP Table: an ERCOT-specific table that lists estimated, real-time 4CP intervals and includes other relevant data series such as storage load due to charging
* Nodal Price Map: Filter by market and select type of data, map criteria, and style.

## Text Components

Text components support Markdown formatting for text and titles.&#x20;

* **Markdown Widget**: Use to add context for other users of the dashboard, take notes, add links to other sites.&#x20;
* **Title:** Single text blocks for labeling dashboard areas.

## Custom Components

Create your own charts to analyze and explore energy data. Check out [Charts](/analytics/charts) for how to build custom analytics for you and your team.&#x20;

* Custom Graph
* Custom Map


# Nodal Analysis

Search and access the 75,000+ point database that powers the Nodal Price Map and analyze pricing nodes in North America.

{% hint style="info" %}
This feature is being actively developed and tested. Visit your [Account Settings](https://www.gridstatus.io/settings/labs) and the Labs tab to get early access. Let us know what you think and reach out to <support@gridstatus.io> to share any feedback or feature requests.&#x20;
{% endhint %}

## Nodal Analysis Overview

<figure><img src="/files/jK74vnMqodOjzvEoBz62" alt=""><figcaption><p>Home page for Nodal Analysis Application.</p></figcaption></figure>

#### How to Search and Filter for Nodes

The Nodal Pricing Application helps you quickly find and explore pricing locations. You can search for nodes directly by name using the keyword search bar, or refine your results using filters based on predefined categories. Filter counts are displayed to show how many locations match each selection.

* **Search Bar:** Type in the name of a node to search across all indexed location names in the database.
* **ISO Filter:** Limit results to a specific ISO or RTO (e.g., ERCOT, PJM, CAISO) to focus your search on a particular market.
* **Location Type**: Filter by node type, such as AP Node, Aggregate, or bus, depending on what is supported in the catalog.
* **Zone**: Refine your search by specific zones or regions within the selected ISO.
* **Geo Data**: Filter nodes that include geographic coordinates.
* **Status**: Choose whether to view only Active nodes or include Retired ones

#### Export Node Locations

<figure><img src="/files/99IIRxGx7WrKElp0Pawd" alt=""><figcaption><p>FiIter applied to export a subset of available nodes and their geo data.</p></figcaption></figure>

After applying filters, the Export button updates to reflect the total number of nodes available for download. Exports respect your current filters. For example, if you filter ERCOT nodes within a specific zone that include geographic data, the exported file will contain only those matching nodes.

The downloaded CSV includes node details and includes latitude and longitude, making it suitable for spatial analysis and custom modeling.

{% hint style="info" %}
This feature is available as part of the Grid Status Enterprise plan. Reach out to sales at <contact@gridstatus.io> to learn more.
{% endhint %}

## Nodal Page Overview

Each nodal page is loaded with information covering historical price data and location details. There are five main areas focus on: the Dataset Heat Map, the Pricing Charts, the Top-Bottom Spread, the Top & Bottom 100 Values, and the Pricing Location Details.&#x20;

<figure><img src="/files/JTBhByxVvgJt3qjF9Vs9" alt=""><figcaption><p>Nodal Analysis page for BECO 34.5 KV TX3.</p></figcaption></figure>

### Dataset Heat Map

The Dataset Heat Map provides an interactive overview of pricing behavior over time and across different LMP components. Use this tool to identify trends, anomalies, and areas of interest within your selected dataset.&#x20;

You can hover over individual heat map cells to see specific price values and compare them to the broader distribution shown in the legend.&#x20;

**Configuration Options**

* **Dataset Selector**: Choose from the available datasets to analyze trends and LMP pricing values.
* **Time Range Filter:** Analyze pricing behavior over different time periods by selecting the last 12 Months, a specific calendar year, or all available historical data.
* **LMP Component Selector:** Choose an available LMP component to display on the heat map. Options include LMP, Energy, Congestion, or Loss.
* **Heatmap Display Mode**: Toggle between Value and Rank. Value shows actual pricing values by hour and rank assigns a value from 1 (lowest) to 24 (highest) to each hour within a day. Rank mode makes it easier to spot which hours are typically the most or least expensive.
* **Custom Value Range:** Adjust the value range located in the legend and set the minimum and maximum values displayed in the heat map.
* **Basis Comparison:** Set the chart to display the basis spread between a selected "base" pricing node and a comparison node. Basis is calculated by subtracting the "Basis to" node price from the Base node price. A positive basis indicates the Base node has higher prices.

### **DART Spread Analysis**

Select **DART** from the Dataset dropdown to analyze the spread between day-ahead and real-time prices at a node. Larger spreads typically indicate changing real-time conditions or forecast uncertainty in the day-ahead market.&#x20;

When viewing DART data, the heat map reveals seasonal and hourly patterns in spread behavior:

* **Positive values** (warmer colors) indicate hours where day-ahead prices were typically higher than real-time
* **Negative values** (cooler colors) indicate hours where real-time prices exceeded day-ahead

You can also isolate DART spreads for individual LMP components (Energy, Congestion, or Loss) using the Component selector to understand what's driving day-ahead versus real-time differences.

### Pricing Charts

<figure><img src="/files/z1izpA2Em01wthCkN9bB" alt=""><figcaption><p>Dropdown menu to select a dataset for nodal analysis.</p></figcaption></figure>

The Pricing Charts provides analytics for the selected pricing node. Use the dropdown menu to select a dataset and charts will automatically update the reflect the pricing data for the node.&#x20;

**Available Chart Types:**

* **Price Profile Charts:** Visualize the median, 25th percentile, and 75th percentile of nodal prices over time. The median represents the midpoint of observed prices and the 25th and 75th percentiles define the interquartile range (IQR).
* **Price Distribution Charts:** Analyze the spread and frequency of price values over time. This helps identify skew, fat tails, negative pricing events, or price clustering around congestion or loss-related volatility.

<figure><img src="/files/K72OvMZVki3FYdAM52h4" alt=""><figcaption><p>LMP Component graphs for BECO 34.5 KV TX3.</p></figcaption></figure>

### Top-Bottom Spread Analysis

<figure><img src="/files/9g8ARYnXj84nf4l0Iwbu" alt=""><figcaption><p>Top-Bottom Spread Chart for Real-Time LMP with Weekly Averages for TB2 and Top-Bottom 100 Values.</p></figcaption></figure>

The Top-Bottom Spread chart quantifies pricing volatility by measuring the difference between the highest and lowest priced hours at a node. This metric helps assess revenue potential for flexible resources like battery storage and demand response, as well as exposure to price swings. The summary metrics show values for average, median, max (or 95th Percentile), and min (or 5th Percentile).

**Configuration Options**

* **Aggregation:** Use the dropdown menu to select aggregation periods to view spread trends by Daily, Weekly Average, Monthly Average, or Yearly Average.
* **Spread Type:** Select TB1, TB2, or TS4 to change the spread calculation:

  * **TB1**: Spread between the single highest and lowest priced values
  * **TB2**: Spread between the average of the top 2 and bottom 2 values
  * **TS4**: Spread using a wider band of values for a smoother volatility measure

  The bar chart displays the selected spread metric over time, making it easy to identify periods with elevated or suppressed price volatility. Use this to spot seasonal patterns or anomalous periods worth investigating further.

The Top & Bottom 100 Values tables list the most extreme pricing intervals for the selected dataset. These tables update based on your dataset selection (Day-Ahead, Real-Time, or DART).

* **Top 100 Values**: The highest priced intervals at this node, ranked by LMP. Use this to identify when and how often price spikes occur.
* **Bottom 100 Values**: The lowest priced intervals, often showing negative prices during periods of oversupply or curtailment.

### Pricing Location Details

<figure><img src="/files/C2zV8wLWL0jpZ1snCuDh" alt="" width="238"><figcaption></figcaption></figure>

The Pricing Location Details section provides metadata and contextual information for each node in the Grid Status database. This helps users better understand a node’s location and availability of historical data.

Available details include:

* **View on Price Map**: Jump directly to the node's position on one of the interactive maps (if geographic data is available).
* **Location Type:** Indicates whether the node is a generator, load, hub, zone, or other category.
* **Zone:** The market zone or subregion the node belongs to, if applicable.
* **Earliest Seen:** The first date the node appeared in any dataset.
* **Latest Seen:** The most recent update for this node’s data.
* **Linked Datasets:** A list of available datasets where this node appears.
* **Nearby Nodes:** A list of other nodes sorted by geographic proximity.
* **Share Link:** Easily copy a direct URL to this node’s detail page.

## Data Coverage

{% hint style="info" %}
Coverage as of February 2026. The nodal coordinates dataset is offered as part of the Grid Status Enterprise plan. Submit requests for adding nodes to <support@gridstatus.io>.
{% endhint %}

| Location Type     | Market | Coverage |
| ----------------- | ------ | -------- |
| Resource Nodes    | ERCOT  | 95%      |
| Price Nodes       | PJM    | 88%      |
| Price Nodes       | IESO   | 98%      |
| Price Nodes       | CAISO  | 74%      |
| Settlement Points | SPP    | 78%      |
| Price Nodes       | ISONE  | 100%     |
| Price Nodes       | NYISO  | 95%      |
| Price Nodes       | MISO   | 83%      |

*Note: Grid Status maps active nodes and not retired nodes. CAISO coverage refers to all CAISO-administered western markets.*


# Constraint Analysis

Analyze transmission congestion and get a constraint-level understanding of market outcomes across all North American ISOs/RTOs.

{% hint style="info" %}
Available for Grid Status Enterprise subscriptions. Request a demo by reaching out to our sales team at <contact@gridstatus.io>.
{% endhint %}

<figure><img src="/files/RQbhmZW4qqJ8Bg2U4WL1" alt="" width="563"><figcaption><p>Shift Factor Map view for 7430_CP6_NG.</p></figcaption></figure>

## Application Overview

The constraint analysis application provides a view into transmission congestion and identifies patterns in the historical and real-time data.

* Quickly identify the constraints driving congestion costs
* Spot which constraints have been getting better, worse, or showing up more often
* Built for traders, analysts, asset operators, and developers across all ISOs

We connect constraints, LMP data, and pricing nodes through **estimated shift factors.**

* See which constraints are binding and driving congestion costs right now
* Identify the binding constraint behind price separation
* Correlate constraints to pricing locations and related market impact

<figure><img src="/files/ntDuyi5pBMqFxt18Yt22" alt=""><figcaption><p>Trends page for 7430_CP6_NG constraint.</p></figcaption></figure>

> ### **Estimated Shift Factors**
>
> We use our vetted historical shadow price and LMP datasets to calculate shift factors for every constraint/contingency pairing. As new data comes in, we continuously update our estimates to optimally explain observed congestion.
>
> Access our shift factors via our API as well as in the application.&#x20;


# Asset Monitoring

<figure><img src="/files/DdfMMSrfOU4zyl5lJsFZ" alt=""><figcaption></figcaption></figure>

{% hint style="info" %}
Available for Grid Status Enterprise subscriptions. Request a demo by reaching out to your account manager or our sales team at <contact@gridstatus.io>.
{% endhint %}

## Application Overview

The Asset Monitoring Application provides a centralized monitoring layer for generation assets tied to specific nodes. Users can register the pricing nodes associated with their assets and track relevant market conditions, including prices, congestion, and basis relationships to basis or hub nodes.

Common use cases include:

* Monitoring generation assets across multiple ISOs
* Tracking price exposure at a custom list of asset-level locations
* Comparing node prices to hub benchmarks
* Evaluating congestion and basis risk
* Monitoring asset performance during major grid events


# Forecast Analysis

An application to visualize how forecast vintages change and measure their accuracy over time.

The Forecast Analysis Application helps you explore how forecasts evolve over time, compare their historical accuracy, and understand the implications for your own operations. The application works with the forecasts datasets already in our data catalog including load forecast by ISO/RTO, renewable generation forecasts, and outage forecasts by fuel or unit.&#x20;

## Application Overview

The Forecast Analysis application is fully interactive, allowing you to tailor the view to your specific needs. You can adjust filters, forecast types, time ranges, and display options to streamline your analysis. This flexibility makes it easy to explore trends, compare vintages, and uncover insights across different markets and forecast types.

There are two main areas to focus on: the application settings and the table/graph forecast.

<figure><img src="/files/HgCW5ekad4PRHcNBzrHq" alt=""><figcaption><p>PJM 5-Minute Wind Forecast showing all vintages in both table and graph format.</p></figcaption></figure>

### Forecast Settings

* **Select ISO:** Choose one or more ISOs/RTOs to filter the forecast data. This limits the analysis to specific markets, helping you focus on region-specific trends and forecast behavior.
* **Select a forecast**: Choose the type of forecast you want to analyze—such as load, solar, wind, outages, or LMP. This setting determines which dataset is used for visualizing forecast vintages and calculating accuracy.
* **Vintages to include**: There are multiple forecast vintages available for each operating interval. Choose from the following options to filter which vintages are used in the application tool. All vintages filters for all forecasts versions for a operating interval.. Latest before selects a single forecast vintage published at least X hours before the operating interval. Within window selects all forecast vintages published at most X hours prior to each operating interval.
* **Collapse Settings**: Select the arrow icon in the panel's upper right corner and make it easier to view the forecast.
* **Date Selector:** Set the date and range for the operating interval. For easy access, quick select time ranges are provided in the left menu.

<figure><img src="/files/Fs0sPugb5WXvqrUgBKBq" alt="" width="375"><figcaption><p>Quick select options for the application date selector.</p></figcaption></figure>

### Data Sources

<figure><img src="/files/l90GnR6dcVP05hI9AYxc" alt="" width="305"><figcaption><p>Data Sources powering the Forecast Analysis Application.</p></figcaption></figure>

This section provides links to the original datasets powering the Forecast Analysis Application. It offers transparency into where the data comes from and how it’s structured. Use this section to explore the source data behind your analysis.

### Display Settings

To analyze forecasts, use interactive charts to visualize forecast vintages and identify trends, shifts, or anomalies. The table view offers a detailed breakdown of forecast values, errors, and accuracy metrics—making it easy to explore the data behind the charts and strengthen your analysis.

<figure><img src="/files/gUgHA8hM09mmVURLJ75t" alt=""><figcaption><p>Controls and interactions available for graph and table views.</p></figcaption></figure>

Reviewing from left to right, the following controls and interactions are available for the graph and table views:

* **Download Shortcut:** Download the graph as an image or export the underlying data for further analysis or reporting.
* **Y-Axis Min**: Set the minimum value for the Y-axis to control the lower bound of the chart. Useful for focusing on a specific range or improving visual clarity.
* **Y-Axis Max**: Set the maximum value for the Y-axis to control the lower bound of the chart. Useful for focusing on a specific range or improving visual clarity.
* **Show Actual Values**: Graph the data series for actual values to compare against forecast vintages.
* **Show Current Time**: Display a vertical reference line on the graph to indicate the current time, helping you quickly compare forecasts against real-time conditions.
* **Show Graph Legend**: Display the color legend on the graph to identify each data series by color. Useful for distinguishing between forecast vintages and actual values.
* **Select Graph/Table Views:** Choose how you want to display the forecast analysis—show both the graph and table, or view only one at a time for a cleaner layout.


# Data Sources

Data Sources allows teams to connect external databases to Grid Status and build custom charts to visualize data within Grid Status dashboards.

{% hint style="info" %}
Interested in connecting a data source? Reaching out to our sales team at <contact@gridstatus.io> and learn more about Grid Status Enterprise subscriptions.
{% endhint %}

## Create a New Data Source

<figure><img src="/files/ed75Bcgz62cbkcQKCfEo" alt=""><figcaption><p>Fields to add a new data source.</p></figcaption></figure>

The Data Sources application provides a secure way to connect an external, SQL database. Once connected, you can register specific data tables as datasets and define the time-series metadata.&#x20;

<figure><img src="/files/T1D19A6abYAhVxKvTFVB" alt=""><figcaption><p>Register data tables as datasets and annotate columns for correct data representation.</p></figcaption></figure>

## Create Charts with Data Sources

<figure><img src="/files/h9qnmigoXygDKuNzJkKA" alt=""><figcaption><p>Custom Chart lookup for data source and the registered dataset. </p></figcaption></figure>

After registering a dataset within the Data Sources application, it becomes available inside the [Charts & Dashboards](https://www.gridstatus.io/dashboards) application.

To add external data to a chart:

1. Navigate to Charts & Dashboards.
2. Create a new Custom Chart or edit an existing one.
3. In the Series section, use the search bar to look up your dataset by name.

Registered datasets from connected Data Sources appear in the dataset dropdown alongside native Grid Status datasets. This allows you to seamlessly combine your connected external data with Grid Status datasets in the same visualization.

## Managing Data Sources

Within each Data Source, users can manage the following:

* **Registered Datasets**: Manage tables exposed to the platform.
* **Source Tables**: View available database tables.
* **Connection:** Update credentials or test the connection.
* **Sharing:** Control access and set roles within your organization.

## Need Help?

If you need assistance configuring your connection or modeling your dataset structure, reach out to <support@gridstatus.io>.


# Data Catalog

A complete list of available Grid Status datasets. Refine your search with keyword search and filtering by source to streamline data discovery.

Open the [Data Catalog](https://www.gridstatus.io/datasets) to browse the application.

<figure><img src="/files/xy68QRCYmr9uZ552keJF" alt=""><figcaption></figcaption></figure>

## How to Search and Filter for Datasets

* **Keyword Search:** The search bar indexes text from every dataset, including dataset descriptions and source IDs.&#x20;
* **Source Menu:** Constrain your search to datasets from a particular source (e.g ERCOT, EIA)
* **Display Settings**: Toggle between viewing datasets in a card view or list view.&#x20;
* **Sort By Menu**: Organize datasets by name, earliest data available, latest data, and last check date.
* **Group by Source**: Toggle the setting to group datasets by their source. In the image below, you can see datasets organized by ISO's ERCOT and PJM.

To configure the catalog view, use the icons in the upper right and select either cards (seen above) or a list.

In the list view, you get additional information:

* **Dataset ID:** Dataset name in the API
* **Earliest Data:** Identify the historical data available for specific datasets.

You can also click on the column headers in order to sort the datasets listed.

The card view allows grouping by source and has sorting options in a selector next to the grouping toggle.

Now let's dive into the dataset pages themselves.

## Dataset Page Overview

Each dataset page is loaded with information. There are four main areas focus on the description, the graph preview, annotations panel, and table preview. We'll go through each element, starting with the description.  Note that the **Status** of the datasets is listed below the dataset name. The status can be active, retired, or deprecated. Contact Grid Status if a dataset is no longer active and you require a recommendation for your use case.

<figure><img src="/files/MmaInmGA1rt0bLsNFAPL" alt=""><figcaption></figcaption></figure>

### Dataset Overview and Description

Power markets are complicated. That statement isn't limited to outcomes, but also applies to the constituent data that informs and defines their systems. In this view, we offer an overview and description. Where possible, we try to write dataset descriptions understandable by humans. There are a few small pieces of recurring notation:

* 💡 an extra tidbit of information or explanation, not purely descriptive of the data itself
* 📝 links to a specific blog where we utilized the dataset
* ⚠️warning for tricky data pitfalls or a note on data provenience or availability

If you see a description with limited or confusing information, reach out and we'll update it right away.&#x20;

### Dataset Annotations

<figure><img src="/files/VuxH4TAGw0Dea7TtpwqC" alt=""><figcaption></figcaption></figure>

For every dataset in our system, we collect dataset details and list them in the annotations section. The available annotation types are listed below.

* **Dataset ID**: id value used to query the dataset from the API. Click the icon to copy the value in order to run a script.&#x20;
* **Source URL**:  the location of the underlying data at its source. In some cases this refers to a more generic data portal as it is not possible to link directly to the original source. If a source ID is listed in the URL, you can query the data catalog by using this identifier in the search bar.
* **Data Frequency**: an annotation we use to track datasets and engineer performant calculations in other places within the Grid Status app. In the above screenshot, the selected dataset was ERCOT SCED, which is an irregular timeseries. 1 hour and 5 minutes are the most common data frequencies.
* **Primary Key**: a column or a set of columns that uniquely identifies each row in the dataset.
* **Time Index Column**: specifies which column in your dataset represents time. This is particularly relevant for time-series data, where values are recorded over a sequence of time points.
* **Subseries Index Column**: identifies distinct individual series within a larger dataset. This is common when you have multiple, independent time series collected in one table.
* **Snowflake Availability**: nearly all datasets are "Available in Snowflake", but reach out if you see one you need is missing.

### Dataset Preview

<figure><img src="/files/bSDHJtJAYeebcUfzYLR5" alt=""><figcaption></figcaption></figure>

You can preview the dataset in table format. To configure the data previews, you can select the following:

* **Timestamp (Table Preview)**: Set timezone for the timestamp column as either market time (local time) or UTC.&#x20;
* **Date Range (Table & Chart Preview)**: Set the date and review available, historical data if you have a <mark style="color:green;">paid Grid Status subscription</mark>.&#x20;

### Data Columns

This section shows the name of every column in the dataset as well as its type.

<figure><img src="/files/QbHKLsf7D2x57oEXWNqt" alt=""><figcaption></figcaption></figure>

### Updates

The Updates tab posts changes made in chronological order, number of rows added, and type of update. Update Types include:

**Incremental**: changes, additions, or deletions that have occurred since the last successful update

**Backfill**: a one-time or infrequent operation performed to retroactively fill in missing historical data or correcting existing historical data within a dataset

<figure><img src="/files/03KNKbuFeGbJV5vU5FIg" alt=""><figcaption></figcaption></figure>

### Audit

The Dataset Audit tab visualizes a dataset’s data availability over time. You can use it to assess data completeness, tracking changes in unique values, or troubleshooting data issues. This data is refreshed daily.

To use, you can configure:

* **High Gradient Mode:** sets the color scale using the minimum and maximum values present in the selected year, while the default mode sets the color scale between zero and a rounded maximum value. High gradient mode can be useful for detecting more subtle changes in values between dates.
* **Year:** select from a dropdown menu and view a calendar year of dataset audits.
* **Metric:** select from *Total Rows, Unique Time Index Values, Unique Subseries Index Values, Unique Publish Time Values* as the options for data visualized.

<figure><img src="/files/ScSmIt2mEuDWe4KucHr6" alt=""><figcaption></figcaption></figure>

### Action Buttons

Finally, we have two buttons to access the data. **View API Code** provides instructions to query a dataset and **Export to File** opens the Data Exporter prefilled with dataset details from the page you're on.

<figure><img src="/files/7mjofoSTDQfThSj4r3mw" alt=""><figcaption></figcaption></figure>


# Data Exporter

Easily download any Grid Status dataset as a CSV file.

## Create an Export

The Data Exporter allows you to download datasets from Grid Status into a CSV file for offline use, modeling, or integration into your own tools. Export limits vary by subscription plan.

You can access export options using the following options:

* **Data Exporter Application**: export directly from the main exporter interface.
* **Download from a Graph**: export the underlying data from any chart or visualization.
* **Export from a Dataset Page**: download data from a dataset table view.

<figure><img src="/files/EY1ihKyYDeNXoS08qAp2" alt="" width="375"><figcaption><p>Application shortcut to open the Data Exporter.</p></figcaption></figure>

## Data Exporter Application

<figure><img src="/files/w0ibOhSOwrlwmuTD6PXg" alt="" width="375"><figcaption><p>Select filters for the dataset to create a new data export.</p></figcaption></figure>

The export drawer shows the subscription plan's current monthly row limit and usage at the top of the window. To create an export, fill out the following information to generate a CSV file.

* **Dataset Name:** Search by the market name or term to refine the list of datasets and select it for your export.
* **Location (if applicable):** Search by node name and select it for your export.
* **Columns:** Select only the necessary columns of data for the CSV file.&#x20;
* **Timezone:** By default, data will be exported in the default timezone of the source it comes from. You also have the option to change it to whatever best matches your use case.
* **Date Range:** Choose the time period that matches your data query needs.
* **Publish Time (if applicable):** Choose from options *All Records, Latest, Latest Report.*

Currently, individual exports are limited to 10M rows for paid plans and 50,000 rows for free plans.&#x20;

## Export Log&#x20;

When you click **Start Export**, the drawer returns you to the **Export Data** view. Here you can monitor your current usage and data limits. Usage of the Data Exporter counts toward the **Monthly Row Exports** limit in your subscription. For more details about your usage, you can navigate to the [***Settings***](https://www.gridstatus.io/settings/usage) page.

<figure><img src="/files/YdOVAZsFtdU3pdUvoOyE" alt="" width="563"><figcaption><p>View of current account usage and exports that are complete or in progress.</p></figcaption></figure>

From this page, you can track exports that are currently in progress as well as review the recent history of completed exports. If you close the drawer while an export is running, the process will continue in the background, and a notification will appear at the bottom of the screen once the export is complete.

<figure><img src="/files/Rlp8vS2uBoIbLhO8HBBp" alt="" width="375"><figcaption><p>Notification for a completed export job.</p></figcaption></figure>

Completed exports are delivered in **.zip format** and remain accessible for up to **7 days**.

## Download from a Graph

<figure><img src="/files/IFCc3BKx8cq7QtcMa4md" alt="" width="375"><figcaption><p>Select the download icon to export data from a graph.</p></figcaption></figure>

When you click the **Download Data** icon, you can download graph data in two formats:

* **Data Exporter**: Opens the Data Exporter application with the dataset pre-selected. The exporter automatically applies the same columns and timeframe used in the graph. From there, you can further customize filters before completing the export.
* **Download Table of Data as a CSV**: Saves all graph data directly to a single CSV file. The exported file reflects the current graph view, including any data series, selected time ranges, and applied formulas.

<figure><img src="/files/mypKjby3PoUGnko5D2HI" alt="" width="375"><figcaption><p>Available graph export options.</p></figcaption></figure>

## Export from a Dataset Page

You can also export data directly from a dataset’s detail page. In the upper-right corner of the preview section, click the export option to open the **Data Exporter**. The dataset will be pre-selected, with all columns included by default

<figure><img src="/files/p8FLFPo4Age3HTfkU29j" alt=""><figcaption><p>Example of Data Exporter shortcut from a dataset page.</p></figcaption></figure>


# Getting Started

The Grid Status API provides access to real-time and historical energy data.

### Authentication

To use the API, you will need to obtain an API key. API keys are used to identify and authenticate your requests to the API. If you don't have an API key, you can request one [here](https://www.gridstatus.io/api).

<figure><img src="/files/pi0baQT7YC86yw7Th4Rn" alt=""><figcaption></figcaption></figure>

Once you have an API key, you can use it to authenticate your requests by adding the `x-api-key` header to your requests or by adding the `api_key` query parameter.

### Hosted API

Our hosted API is designed to provide users with a single location where the raw data has been processed and stored, resulting in several advantages:

1. Faster and more flexible querying
2. Generally, more historical data availability
3. Continued availability even if any of the ISO sources go offline.


# API References

{% openapi src="<https://api.gridstatus.io/openapi.json>" path="/v1/datasets" method="get" %}
<https://api.gridstatus.io/openapi.json>
{% endopenapi %}

{% openapi src="<https://api.gridstatus.io/openapi.json>" path="/v1/datasets/{dataset}" method="get" %}
<https://api.gridstatus.io/openapi.json>
{% endopenapi %}

{% openapi src="<https://api.gridstatus.io/openapi.json>" path="/v1/datasets/{dataset}/query" method="get" %}
<https://api.gridstatus.io/openapi.json>
{% endopenapi %}

{% openapi src="<https://api.gridstatus.io/openapi.json>" path="/v1/datasets/{dataset}/query/{filter\_column\_id}/{filter\_value\_path}" method="get" %}
<https://api.gridstatus.io/openapi.json>
{% endopenapi %}

{% openapi src="<https://api.gridstatus.io/openapi.json>" path="/v1/dataset-updates/{dataset}" method="get" %}
<https://api.gridstatus.io/openapi.json>
{% endopenapi %}

{% openapi src="<https://api.gridstatus.io/openapi.json>" path="/v1/reports/daily\_peak/{iso}" method="get" %}
<https://api.gridstatus.io/openapi.json>
{% endopenapi %}

{% openapi src="<https://api.gridstatus.io/openapi.json>" path="/v1/" method="get" %}
<https://api.gridstatus.io/openapi.json>
{% endopenapi %}


# Rate Limits

To mitigate misuse and manage capacity on our API, we have implemented limits on how much an organization can use the Grid Status API.

We have two tiers for rate limits.&#x20;

### Basic

| Interval   | Requests Allowed |
| ---------- | ---------------- |
| Per Second | 1 requests       |
| Per Minute | 30 requests      |
| Per Hour   | 600 requests     |

### Standard

| Interval   | Requests Allowed |
| ---------- | ---------------- |
| Per Second | 6 requests       |
| Per Minute | 60 requests      |
| Per Hour   | 1200 requests    |


# API Authentication

To use the API, you will need to obtain an API key. API keys are used to identify and authenticate your requests to the API. If you don't have an API key, you can make one by clicking button below

<a href="https://www.gridstatus.io/settings/api" class="button primary">Get API Key</a>

Once you have your API key, you can authenticate in one of two ways:

**Option 1: Add it to the header**

```
curl -H "Accept-Encoding: br, gzip" -H "x-api-key: YOUR_API_KEY" https://api.gridstatus.io/v1/datasets
```

**Option 2: Use the `api_key` query parameter**

```bash
curl -H "Accept-Encoding: br, gzip" "https://api.gridstatus.io/v1/datasets?api_key=YOUR_API_KEY"
```

Make sure to replace `'YOUR_API_KEY'` with your actual API key.

For instructions on authenticating via the Python client, please[ refer to this page](/developers/getting-started/python-client).


# Python Client

We provide a Python client library that you can use to interact with the API. You can find the library [here](https://github.com/gridstatus/gridstatusio).

#### Installation

`gridstatusio` supports Python 3.10+. Install with pip (or uv):

```
pip install gridstatusio
```

Upgrade using:

```
python -m pip install --upgrade gridstatusio
```

#### Authentication

You can authenticate using your API key in one of two ways:

1. **Set an environment variable**:

```
export GRIDSTATUS_API_KEY=your_api_key
```

2. **Pass the API key directly** when creating the client:

```
from gridstatusio import GridStatusClient

client = GridStatusClient(api_key="your_api_key")
```


# Handling Time

By default, all datetime values returned by the API are in UTC. The API provides `start_time` and `end_time` query parameters to filter results based on a specific time range. These parameters only filter on a dataset's `time_index_column`. If a dataset does not have a `time_index_column`, these parameters do not apply.

* `start_time`: Specifies the start of the time range for the query. Records with a timestamp equal to or greater than the `start_time` will be returned. Format: `YYYY-MM-DDTHH:MM-HH:MM`
* `end_time`: Specifies the end of the time range for the query. The `end_time` is not included. Records with a timestamp less than the `end_time` will be returned. Format: `YYYY-MM-DDTHH:MM-HH:MM`

A few notes about how datetime parameters are handled:

* If no `start_time` or `end_time` are specified, the API will return all records
* If no timezone or offset is specified, the API defaults to using UTC. For example, `2021-01-01T00:00` is equivalent to `2021-01-01T00:00+00:00`.
* If only a date is provided without a time, it is assumed to be 00:00 of that day. For example, `2021-01-01` is equivalent to `2021-01-01T00:00+00:00`.
* You can provide a timezone offset in the format `+HH:MM` or `-HH:MM`. For example, `2021-01-01T00:00-05:00` is equivalent to `2021-01-01T05:00+00:00`.

Examples of valid time strings:

* `2021-01-01T00:00+00:00`
* `2021-01-01T00:00-05:00`
* `2021-01-01T00:00`
* `2021-01-01`


# Pagination

The API implements pagination. By default, the page size is set based on your subscription. You can change the size of the page with the `page_size` parameter, up to the maximum allowed by your subscription. For instance, to access the second page where each page has 100 rows and you are using offset based pagination, append `?page=2&page_size=100` to your request URL.

Keep in mind that retrieving many records from large datasets might necessitate multiple requests. See below for information on how to determine if there is a next page.

### Offset vs Cursor Pagination

* The API supports both offset and cursor pagination.
* Cursor pagination is used when the `cursor` parameter is provided.
* Cursor pagination is more efficient than offset pagination for large datasets because it doesn't require the API to scan through all the records to find the next page.
* For cursor pagination, for the first request, append `cursor=""` to your request to get the first page. For subsequent requests, use the `cursor` value from the meta data of the previous response.
* Offset pagination requires sending the `page` parameter to specify the page number.

#### JSON Response Format <a href="#json-response-format" id="json-response-format"></a>

When using the JSON response format, the API will return a meta object in the response that includes information about the current page, the limit, whether there are more records available (hasNextPage), and the cursor for using cursor pagination.

```json
{
  "status": "success",
  "data": [...],
  "meta": {
    "page": 1,
    "page_size": 50000,
    "limit": 1000,
    "hasNextPage": true
    "cursor": "dGhpcyBpcyBhIGxvbmcgc3RyaW5n"
  }
}
```

#### Streaming the JSON Response <a href="#streaming-json-response" id="streaming-json-response"></a>

For large JSON queries you can opt into a streaming response by sending the `X-Stream: true` request header. The API then streams rows directly from the database as they are read, instead of buffering the entire result set in memory first, which lowers time-to-first-byte and memory use. The response body is identical to the non-streaming JSON format, including the `meta` object.

In streaming mode the pagination response headers (such as `X-Has-Next-Page`) are not sent, because the response headers are committed before all rows are read. Read pagination from the JSON `meta.hasNextPage` and `meta.cursor` fields, which are populated the same way on both the streaming and non-streaming paths. Streaming applies to the JSON response format only.

#### CSV Response Format <a href="#csv-response-format" id="csv-response-format"></a>

When using the CSV response format, the API will return the pagination information as headers in the response:

* `X-Page`: The current page number
* `X-Page-Size`: The page size
* `X-Limit`: The maximum number of rows to return across all pages
* `X-Has-Next-Page`: A boolean value indicating whether there are more records available


# Response Format

## JSON vs CSV Response

The API supports JSON and CSV return formats. The default return format is JSON. JSON is generally easier to work with in code, while CSV is more suitable for downloading the data to a spreadsheet or other data analysis tools.

You can specify the return format by adding the `return_format` query parameter to your request. For example, to get the data in CSV format, you would add `?return_format=csv` to the end of your request.

#### JSON <a href="#json" id="json"></a>

There are two JSON return formats: `array_of_objects` and `array_of_arrays`. The `array_of_objects` format is the default format. The `array_of_arrays` format is useful for minimizing the size of the response.

#### CSV <a href="#csv" id="csv"></a>

The CSV return format is useful for downloading the data to a spreadsheet.

## Response Compression

The API compresses responses with **brotli** or **gzip** whenever your client sends an `Accept-Encoding` request header — independent of the return format above. On large dataset queries this reduces the transfer by up to \~20x (for example, a 60 MB JSON response drops to roughly 3 MB), so downloads are faster and use far less bandwidth.

Most HTTP clients — including the Grid Status Python client, `requests`, `httpx`, and web browsers — request and decompress responses automatically. If your integration does not, add the header explicitly (`Accept-Encoding: br, gzip`, or pass `--compressed` to curl). See [Best Practices](/developers/guides/best-practices) for examples.


# Publish Time

## Overview

The Grid Status API provides sophisticated publish time filtering capabilities that allow you to control which data points are returned based on when they were published or reported. This is particularly useful for forecasting data, where multiple predictions may exist for the same operating time but were published at different times.

{% hint style="info" %}
Publish time filtering is only available for datasets that have a `publish_time_column`. You can identify these datasets by checking the dataset metadata - datasets with publish time capabilities will have a non-null `publish_time_column` field.
{% endhint %}

## Available Publish Time Parameters

### 1. `publish_time` - Primary Filtering Parameter

The `publish_time` parameter is the main way to filter data based on publication timing. It supports several different modes:

#### 1.1. `latest_report` - Most Recent Report

Returns only data from the most recently published report across the entire dataset.

**Use Case:** Get the very latest forecast or report available

**Example:**

{% tabs %}
{% tab title="Shell" %}

```shell
curl -H "Accept-Encoding: br, gzip" "https://api.gridstatus.io/v1/datasets/ercot_load_forecast_by_forecast_zone/query?publish_time=latest_report&limit=5&api_key=YOUR_API_KEY"
```

{% endtab %}

{% tab title="Python" %}

```python
client.get_dataset(
  'ercot_load_forecast_by_forecast_zone',
  publish_time="latest_report",
  limit=5
)
```

{% endtab %}
{% endtabs %}

#### 1.2. `latest` - Latest for Each Time Index

For any given operating timestamp, returns the most recently published data point.

**Use Case:** Get the most up-to-date forecast for each operating hour

**Dataset Requirement:** Requires the dataset to have both a `publish_time_column` and `time_index_column`

**Example:**

{% tabs %}
{% tab title="Shell" %}

```shell
curl -H "Accept-Encoding: br, gzip" "https://api.gridstatus.io/v1/datasets/ercot_load_forecast_by_forecast_zone/query?publish_time=latest&start_time=2024-01-01&end_time=2024-01-02&limit=10&api_key=YOUR_API_KEY"
```

{% endtab %}

{% tab title="Python" %}

```python
client.get_dataset(
  'ercot_load_forecast_by_forecast_zone',
  publish_time="latest",
  start="2024-01-01",
  end="2024-01-02",
  limit=10
)
```

{% endtab %}
{% endtabs %}

**Response:** For each `interval_start_utc` timestamp, returns the record with the most recent `publish_time_utc`.

#### 1.3. Specific Timestamp

Provide an ISO 8601 timestamp to get only data published at that exact time.

**Use Case:** Retrieve data from a specific forecast time

**Example:**

{% tabs %}
{% tab title="Shell" %}

```shell
curl -H "Accept-Encoding: br, gzip" "https://api.gridstatus.io/v1/datasets/ercot_load_forecast_by_forecast_zone/query?publish_time=2024-01-01T12:30:00Z&start_time=2024-01-01&end_time=2024-01-02&limit=5&api_key=YOUR_API_KEY"
```

{% endtab %}

{% tab title="Python" %}

```python
client.get_dataset(
  'ercot_load_forecast_by_forecast_zone',
  publish_time="2024-01-01T12:30:00Z",
  start="2024-01-01",
  end="2024-01-02",
  limit=5
)
```

{% endtab %}
{% endtabs %}

#### 1.4. `latest_before` - Latest Before Cutoff

Returns the most recent forecast for each operating time where the publish time is before or equal to a calculated cutoff time relative to each operating time.

**Formats:**

| Format                              | Description                                                                                                                      |
| ----------------------------------- | -------------------------------------------------------------------------------------------------------------------------------- |
| `latest_before`                     | Shorthand for `latest_before:-0 hours`. Returns the latest forecast published at or before each operating time                   |
| `latest_before:<offset>`            | e.g., `latest_before:-6 hours`. Retrieves forecasts published at least 6 hours before each operating time                        |
| `latest_before:<offset>@<HH:MM:SS>` | e.g., `latest_before:-1 day@10:30:00`. Retrieves forecasts published at or before 10:30 AM on the day before each operating time |

**Use Case:** Get forecasts published at least X time before the operating time, useful for day-ahead vs real-time analysis

**Examples:**

Basic offset:

{% tabs %}
{% tab title="Shell" %}

```shell
curl -H "Accept-Encoding: br, gzip" "https://api.gridstatus.io/v1/datasets/ercot_load_forecast_by_forecast_zone/query?publish_time=latest_before:-6%20hours&start_time=2024-01-01&end_time=2024-01-02&limit=5&api_key=YOUR_API_KEY"
```

{% endtab %}

{% tab title="Python" %}

```python
client.get_dataset(
  'ercot_load_forecast_by_forecast_zone',
  publish_time="latest_before:-6 hours",
  start="2024-01-01",
  end="2024-01-02",
  limit=5
)
```

{% endtab %}
{% endtabs %}

With specific time:

{% tabs %}
{% tab title="Shell" %}

```shell
curl -H "Accept-Encoding: br, gzip" "https://api.gridstatus.io/v1/datasets/ercot_load_forecast_by_forecast_zone/query?publish_time=latest_before:-1%20day@10:30:00&start_time=2024-01-01&end_time=2024-01-02&limit=5&api_key=YOUR_API_KEY"
```

{% endtab %}

{% tab title="Python" %}

```python
client.get_dataset(
  'ercot_load_forecast_by_forecast_zone',
  publish_time="latest_before:-1 day@10:30:00",
  start="2024-01-01",
  end="2024-01-02",
  limit=5
)
```

{% endtab %}
{% endtabs %}

**Logic:**

* For `latest_before:-6 hours`: `publish_time ≤ operating_time - 6 hours`
* For `latest_before:-1 day@10:30:00`: `publish_time ≤ 10:30:00 on (operating_time - 1 day)`

#### 1.5. `window` - Time Window

Returns all forecasts published within a specific time window relative to the operating time.

**Formats:**

| Format                       | Description                                                                                                           |
| ---------------------------- | --------------------------------------------------------------------------------------------------------------------- |
| `window:<offset>`            | e.g., `window:-6 hours`. Returns all forecasts published in the 6 hours leading up to each operating time             |
| `window:<offset>@<HH:MM:SS>` | e.g., `window:-1 day@10:00:00`. Returns all forecasts published from 10:00 AM the day before up to the operating time |

**Use Case:** Analyze all forecasts published within a specific timeframe before the operating time

**Example:**

{% tabs %}
{% tab title="Shell" %}

```shell
curl -H "Accept-Encoding: br, gzip" "https://api.gridstatus.io/v1/datasets/ercot_load_forecast_by_forecast_zone/query?publish_time=window:-6%20hours&start_time=2024-01-01&end_time=2024-01-02&limit=10&api_key=YOUR_API_KEY"
```

{% endtab %}

{% tab title="Python" %}

```python
client.get_dataset(
  'ercot_load_forecast_by_forecast_zone',
  publish_time="window:-6 hours",
  start="2024-01-01",
  end="2024-01-02",
  limit=10
)
```

{% endtab %}
{% endtabs %}

**Logic:** `(operating_time + offset) ≤ publish_time ≤ operating_time`

For `window:-6 hours`: `(operating_time - 6 hours) ≤ publish_time ≤ operating_time`

***

### 2. `publish_time_start` - Start Range Filter

Filter data to include only records published on or after this timestamp.

* **Use Case:** Get all data published since a specific date/time
* **Cannot be used with:** `publish_time` parameter
* **Format:** ISO 8601 datetime string

**Example:**

{% tabs %}
{% tab title="Shell" %}

```shell
curl -H "Accept-Encoding: br, gzip" "https://api.gridstatus.io/v1/datasets/ercot_load_forecast_by_forecast_zone/query?publish_time_start=2024-01-01T00:00:00Z&start_time=2024-01-01&end_time=2024-01-02&limit=10&api_key=YOUR_API_KEY"
```

{% endtab %}

{% tab title="Python" %}

```python
client.get_dataset(
  'ercot_load_forecast_by_forecast_zone',
  publish_time_start="2024-01-01T00:00:00Z",
  start="2024-01-01",
  end="2024-01-02",
  limit=10
)
```

{% endtab %}
{% endtabs %}

***

### 3. `publish_time_end` - End Range Filter

Filter data to include only records published before this timestamp (exclusive).

* **Use Case:** Get historical data published before a specific cutoff
* **Cannot be used with:** `publish_time` parameter
* **Format:** ISO 8601 datetime string

**Example:**

{% tabs %}
{% tab title="Shell" %}

```shell
curl -H "Accept-Encoding: br, gzip" "https://api.gridstatus.io/v1/datasets/ercot_load_forecast_by_forecast_zone/query?publish_time_end=2024-01-01T12:00:00Z&start_time=2024-01-01&end_time=2024-01-02&limit=10&api_key=YOUR_API_KEY"
```

{% endtab %}

{% tab title="Python" %}

```python
client.get_dataset(
  'ercot_load_forecast_by_forecast_zone',
  publish_time_end="2024-01-01T12:00:00Z",
  start="2024-01-01",
  end="2024-01-02",
  limit=10
)
```

{% endtab %}
{% endtabs %}

***

### 4. Combined Range Filtering

You can use both `publish_time_start` and `publish_time_end` together to create a specific publication time window.

**Example:**

{% tabs %}
{% tab title="Shell" %}

```shell
curl -H "Accept-Encoding: br, gzip" "https://api.gridstatus.io/v1/datasets/ercot_load_forecast_by_forecast_zone/query?publish_time_start=2024-01-01T06:00:00Z&publish_time_end=2024-01-01T18:00:00Z&start_time=2024-01-01&end_time=2024-01-02&limit=10&api_key=YOUR_API_KEY"
```

{% endtab %}

{% tab title="Python" %}

```python
client.get_dataset(
  'ercot_load_forecast_by_forecast_zone',
  publish_time_start="2024-01-01T06:00:00Z",
  publish_time_end="2024-01-01T18:00:00Z",
  start="2024-01-01",
  end="2024-01-02",
  limit=10
)
```

{% endtab %}
{% endtabs %}

This returns all forecasts published between 6 AM and 6 PM on January 1st, 2024.

***

## Offset Format Specification

For `latest_before` and `window` parameters, the offset format follows these rules:

### Basic Offset Format

`<amount> <unit>` where:

* **amount:** Number (can be negative, positive, or decimal)
* **unit:** One of: `seconds`, `minutes`, `hours`, `days`, `weeks`, `months`, `years`

**Examples:**

* `-6 hours`
* `1.5 days`
* `-30 minutes`
* `2 weeks`

### Time-Specific Format

`<offset>@<HH:MM:SS>` where:

* **offset:** Basic offset as above
* **@:** Separator
* **HH:MM:SS:** Specific time in 24-hour format

**Examples:**

* `-1 day@10:30:00` - 10:30 AM on the previous day
* `-2 days@14:15:30` - 2:15:30 PM two days prior

### URL Encoding

{% hint style="warning" %}
When using offsets in URLs, remember to URL-encode spaces:

* `-6 hours` becomes `-6%20hours`
* `-1 day@10:30:00` becomes `-1%20day@10:30:00`
  {% endhint %}

***

## Common Use Cases and Examples

### 1. Day-Ahead vs Real-Time Forecast Analysis

Compare day-ahead forecasts (published \~24 hours before) with near-real-time forecasts:

**Day-ahead forecasts:**

{% tabs %}
{% tab title="Shell" %}

```shell
curl -H "Accept-Encoding: br, gzip" "https://api.gridstatus.io/v1/datasets/ercot_load_forecast_by_forecast_zone/query?publish_time=latest_before:-20%20hours&start_time=2024-01-01&end_time=2024-01-02&api_key=YOUR_API_KEY"
```

{% endtab %}

{% tab title="Python" %}

```python
client.get_dataset(
  'ercot_load_forecast_by_forecast_zone',
  publish_time="latest_before:-20 hours",
  start="2024-01-01",
  end="2024-01-02"
)
```

{% endtab %}
{% endtabs %}

**Near real-time forecasts:**

{% tabs %}
{% tab title="Shell" %}

```shell
curl -H "Accept-Encoding: br, gzip" "https://api.gridstatus.io/v1/datasets/ercot_load_forecast_by_forecast_zone/query?publish_time=latest_before:-1%20hour&start_time=2024-01-01&end_time=2024-01-02&api_key=YOUR_API_KEY"
```

{% endtab %}

{% tab title="Python" %}

```python
client.get_dataset(
  'ercot_load_forecast_by_forecast_zone',
  publish_time="latest_before:-1 hour",
  start="2024-01-01",
  end="2024-01-02"
)
```

{% endtab %}
{% endtabs %}

### 2. Morning Forecast Analysis

Get forecasts published during morning hours (6 AM - 12 PM):

{% tabs %}
{% tab title="Shell" %}

```shell
curl -H "Accept-Encoding: br, gzip" "https://api.gridstatus.io/v1/datasets/ercot_load_forecast_by_forecast_zone/query?publish_time_start=2024-01-01T06:00:00Z&publish_time_end=2024-01-01T12:00:00Z&start_time=2024-01-01&end_time=2024-01-02&api_key=YOUR_API_KEY"
```

{% endtab %}

{% tab title="Python" %}

```python
client.get_dataset(
  'ercot_load_forecast_by_forecast_zone',
  publish_time_start="2024-01-01T06:00:00Z",
  publish_time_end="2024-01-01T12:00:00Z",
  start="2024-01-01",
  end="2024-01-02"
)
```

{% endtab %}
{% endtabs %}

### 3. Forecast Revision Analysis

Analyze how forecasts change over time by getting all forecasts in a 6-hour window before operating time:

{% tabs %}
{% tab title="Shell" %}

```shell
curl -H "Accept-Encoding: br, gzip" "https://api.gridstatus.io/v1/datasets/ercot_load_forecast_by_forecast_zone/query?publish_time=window:-6%20hours&start_time=2024-01-01T12:00:00Z&end_time=2024-01-01T18:00:00Z&api_key=YOUR_API_KEY"
```

{% endtab %}

{% tab title="Python" %}

```python
client.get_dataset(
  'ercot_load_forecast_by_forecast_zone',
  publish_time="window:-6 hours",
  start="2024-01-01T12:00:00Z",
  end="2024-01-01T18:00:00Z"
)
```

{% endtab %}
{% endtabs %}

### 4. Historical Snapshot

Get the most recent data as it was available at a specific point in time:

{% tabs %}
{% tab title="Shell" %}

```shell
curl -H "Accept-Encoding: br, gzip" "https://api.gridstatus.io/v1/datasets/ercot_load_forecast_by_forecast_zone/query?publish_time=2024-07-01T00:30:00Z&start_time=2024-07-01&end_time=2024-07-02&api_key=YOUR_API_KEY"
```

{% endtab %}

{% tab title="Python" %}

```python
client.get_dataset(
  'ercot_load_forecast_by_forecast_zone',
  publish_time="2024-07-01T00:30:00Z",
  start="2024-07-01",
  end="2024-07-02"
)
```

{% endtab %}
{% endtabs %}

***

## Response Format

All responses include the `publish_time_utc` column when available, allowing you to verify the publication timing:

```json
{
  "status_code": 200,
  "data": [
    {
      "interval_start_utc": "2024-01-01T00:00:00+00:00",
      "interval_end_utc": "2024-01-01T01:00:00+00:00",
      "publish_time_utc": "2023-12-31T18:30:00+00:00",
      "north": 15543.961113146968,
      "south": 11921.243918188475,
      "west": 5854.474702258297,
      "houston": 11600.86030546875,
      "system_total": 44920.54003906249
    }
  ],
  "meta": {
    "page": 1,
    "limit": 10,
    "hasNextPage": false
  },
  "dataset_metadata": {
    "publish_time_column": "publish_time_utc",
    "time_index_column": "interval_start_utc"
  }
}
```

***

## Error Handling and Validation

### Common Errors

**Invalid Offset Format**

```json
{
  "status_code": 400,
  "detail": "Invalid offset format: -6hour. Expected format: '-6 hours' or '1 day'"
}
```

**Invalid Time Format**

```json
{
  "status_code": 400,
  "detail": "Invalid time format: 25:00:00. Expected HH:MM:SS"
}
```

**Dataset Without Publish Time**

```json
{
  "status_code": 400,
  "detail": "A dataset must have a time index to use 'latest' or 'latest_before:' options. Only 'latest_report' or a timestamp publish time are supported for datasets without a time index"
}
```

**Conflicting Parameters**

```json
{
  "status_code": 400,
  "detail": "Cannot use publish_time with publish_time_start or publish_time_end"
}
```

***

## Best Practices

### 1. Check Dataset Compatibility

Before using publish time filtering, verify that the dataset has a `publish_time_column`:

```shell
curl -H "Accept-Encoding: br, gzip" "https://api.gridstatus.io/v1/datasets/ercot_load_forecast_by_forecast_zone?api_key=YOUR_API_KEY"
```

Look for `"publish_time_column": "publish_time_utc"` in the response.

### 2. Use Appropriate Time Zones

Use `timezone="market"` when your publish-time filter should be interpreted in the dataset's market timezone. This is especially useful for filters like `latest_before:-1 day@10:00:00`, where the cutoff should follow the market's local clock and daylight saving time rules.

### 3. Limit Result Sets

Publish time filtering can return large datasets. Always use limit parameters appropriately:

{% tabs %}
{% tab title="Shell" %}

```shell
curl -H "Accept-Encoding: br, gzip" "https://api.gridstatus.io/v1/datasets/ercot_load_forecast_by_forecast_zone/query?publish_time=window:-24%20hours&limit=1000&start_time=2024-01-01&end_time=2024-01-02&api_key=YOUR_API_KEY"
```

{% endtab %}

{% tab title="Python" %}

```python
client.get_dataset(
  'ercot_load_forecast_by_forecast_zone',
  publish_time="window:-24 hours",
  start="2024-01-01",
  end="2024-01-02",
  limit=1000
)
```

{% endtab %}
{% endtabs %}

### 4. Combine with Other Filters

Publish time filters work well with other parameters like `start_time`, `end_time`, and column filters:

{% tabs %}
{% tab title="Shell" %}

```shell
curl -H "Accept-Encoding: br, gzip" "https://api.gridstatus.io/v1/datasets/ercot_load_forecast_by_forecast_zone/query?publish_time=latest&start_time=2024-01-01&end_time=2024-01-02&columns=interval_start_utc,publish_time_utc,system_total&api_key=YOUR_API_KEY"
```

{% endtab %}

{% tab title="Python" %}

```python
client.get_dataset(
  'ercot_load_forecast_by_forecast_zone',
  publish_time="latest",
  start="2024-01-01",
  end="2024-01-02",
  columns=["interval_start_utc", "publish_time_utc", "system_total"]
)
```

{% endtab %}
{% endtabs %}

### 5. Performance Considerations

* `latest_report` is typically the fastest option as it returns the smallest dataset
* `window` operations can be slower for large time ranges
* Consider using pagination for large result sets

***

## Timezone Handling

The API accepts a `timezone` parameter that affects how publish time calculations are performed:

{% tabs %}
{% tab title="Shell" %}

```shell
curl -H "Accept-Encoding: br, gzip" "https://api.gridstatus.io/v1/datasets/ercot_load_forecast_by_forecast_zone/query?publish_time=latest_before:-1%20day@10:30:00&timezone=America/Chicago&start_time=2024-01-01&end_time=2024-01-02&api_key=YOUR_API_KEY"
```

{% endtab %}

{% tab title="Python" %}

```python
client.get_dataset(
  'ercot_load_forecast_by_forecast_zone',
  publish_time="latest_before:-1 day@10:30:00",
  timezone="America/Chicago",
  start="2024-01-01",
  end="2024-01-02"
)
```

{% endtab %}
{% endtabs %}

When a timezone is specified:

* The time calculations for `@HH:MM:SS` formats are performed in the specified timezone
* The input timestamps are converted to the specified timezone before processing
* Results are still returned in UTC

***

## Summary

The Grid Status API's publish time filtering provides powerful capabilities for:

* **Getting the latest available data** (`latest`, `latest_report`)
* **Historical analysis** (`latest_before` with timestamps)
* **Forecast revision tracking** (`window` operations)
* **Time-based publication filtering** (`publish_time_start`, `publish_time_end`)

These features enable sophisticated analysis of how forecasts evolve over time and allow users to recreate historical views of data as it was available at specific points in time.


# Query Parameters

Complete reference for /v1/datasets/{dataset\_id}/query, the primary end point for pulling data.

This guide shows parameters for both the direct API (cURL) and the Python client (`gridstatusio`).

## Quick Reference

| I want to...                               | cURL Parameter                                         | Python Client Parameter                                           |
| ------------------------------------------ | ------------------------------------------------------ | ----------------------------------------------------------------- |
| Get latest data point                      | `time=latest`                                          | Use `start`, `end` with `limit=1` and query recent data           |
| Query a date range                         | `start_time`, `end_time`                               | `start`, `end`                                                    |
| Filter by location                         | `filter_column=location&filter_value=HB_HOUSTON`       | `filter_column="location"`, `filter_value="HB_HOUSTON"`           |
| Filter multiple values                     | `filter_operator=in&filter_value=HB_HOUSTON,HB_NORTH`  | `filter_operator="in"`, `filter_value=["HB_HOUSTON", "HB_NORTH"]` |
| Find values above threshold                | `filter_column=lmp&filter_operator=>&filter_value=100` | `filter_column="lmp"`, `filter_operator=">"`, `filter_value=100`  |
| Select specific columns                    | `columns=interval_start_utc,lmp`                       | `columns=["interval_start_utc", "lmp"]`                           |
| Get hourly averages                        | `resample_frequency=1 hour&resample_function=mean`     | `resample="1 hour"`, `resample_function="mean"`                   |
| Get daily peaks                            | `resample_frequency=1 day&resample_function=max`       | `resample="1 day"`, `resample_function="max"`                     |
| Convert to a specific timezone             | `timezone=America/Chicago`                             | `timezone="America/Chicago"`                                      |
| Convert to the market timezone for the ISO | `timezone=market`                                      | `timezone="market"`                                               |
| Get newest first                           | `order=desc`                                           | *(handled internally by client)*                                  |
| Limit rows returned                        | `limit=1000`                                           | `limit=1000`                                                      |
| Download as CSV                            | `return_format=csv`                                    | Set `request_format="csv"` in client constructor                  |
| Get latest forecast                        | `publish_time=latest`                                  | `publish_time="latest"`                                           |
| Get day-ahead forecast                     | `publish_time=latest_before:-1 day`                    | `publish_time="latest_before:-1 day"`                             |

## Time Filtering

### `start_time` / `end_time`

Filter by the dataset's time index column.

| cURL Parameter | Python Client Parameter | Type              | Description                            |
| -------------- | ----------------------- | ----------------- | -------------------------------------- |
| `start_time`   | `start`                 | ISO 8601 datetime | Data on or after this time (inclusive) |
| `end_time`     | `end`                   | ISO 8601 datetime | Data before this time (exclusive)      |

Formats accepted:

* `2026-01-01` (assumes midnight UTC)
* `2026-01-01T00:00:00`
* `2026-01-01T00:00:00Z`
* `2026-01-01T00:00:00-05:00` (with offset)

{% code title="cURL" %}

```shell
curl -H "Accept-Encoding: br, gzip" "https://api.gridstatus.io/v1/datasets/ercot_fuel_mix/query?start_time=2026-01-01&end_time=2026-01-02&api_key=YOUR_API_KEY"
```

{% endcode %}

{% code title="Python" %}

```python
import gridstatusio as gs

client = gs.GridStatusClient(api_key="YOUR_API_KEY")

df = client.get_dataset(
    "ercot_fuel_mix",
    start="2026-01-01",
    end="2026-01-02",
)
```

{% endcode %}

### `time`

Query for a specific point in time or the latest data. **Note:** The `time` parameter is only available via the direct API (cURL). In the Python client, use `start`/`end` with `limit=1` to achieve similar results.

| cURL Parameter | Python Client     | Value              | Description            |
| -------------- | ----------------- | ------------------ | ---------------------- |
| `time`         | *(not available)* | `latest`           | Most recent data point |
| `time`         | *(not available)* | ISO 8601 timestamp | Data at exact time     |

{% code title="cURL" %}

```shell
# Get latest data
curl -H "Accept-Encoding: br, gzip" "https://api.gridstatus.io/v1/datasets/ercot_fuel_mix/query?time=latest&api_key=YOUR_API_KEY"
```

{% endcode %}

{% code title="Python" %}

```python
import gridstatusio as gs
from datetime import datetime, timedelta, timezone

client = gs.GridStatusClient(api_key="YOUR_API_KEY")

# Get latest data by querying recent time range with limit
df = client.get_dataset(
    "ercot_fuel_mix",
    start=datetime.now(timezone.utc) - timedelta(hours=1),
    end=datetime.now(timezone.utc),
    limit=1,
)
```

{% endcode %}

### `time_comparison`

Comparison operator for the `time` parameter. **Note:** Only available via the direct API (cURL).

| cURL Parameter    | Python Client     | Value | Description           |
| ----------------- | ----------------- | ----- | --------------------- |
| `time_comparison` | *(not available)* | `=`   | Exact match (default) |
| `time_comparison` | *(not available)* | `>`   | After the time        |
| `time_comparison` | *(not available)* | `>=`  | On or after           |
| `time_comparison` | *(not available)* | `<`   | Before the time       |
| `time_comparison` | *(not available)* | `<=`  | On or before          |

## Publish Time Filtering

For datasets with forecasts or multiple report versions. Only applies to datasets with a `publish_time_column`.

### `publish_time`

| cURL Parameter | Python Client Parameter | Value                             | Description                                              |
| -------------- | ----------------------- | --------------------------------- | -------------------------------------------------------- |
| `publish_time` | `publish_time`          | `latest_report`                   | Only the most recently published report                  |
| `publish_time` | `publish_time`          | `latest`                          | For each timestamp, the most recent forecast             |
| `publish_time` | `publish_time`          | ISO 8601 timestamp                | Records published at exact time                          |
| `publish_time` | `publish_time`          | `latest_before:<offset>`          | Latest forecast published before operating time + offset |
| `publish_time` | `publish_time`          | `latest_before:<offset>@HH:MM:SS` | Latest forecast before specific time on offset day       |
| `publish_time` | `publish_time`          | `window:<offset>`                 | All forecasts between offset and operating time          |

Offset format: `<number> <unit>` where unit is `seconds`, `minutes`, `hours`, `days`, `weeks`, `months`, `years`

{% code title="cURL" %}

```shell
# Get the most recent forecast for each hour
curl -H "Accept-Encoding: br, gzip" "https://api.gridstatus.io/v1/datasets/ercot_load_forecast/query?publish_time=latest&start_time=2026-01-01&end_time=2026-01-02&api_key=YOUR_API_KEY"

# Get day-ahead forecasts (published at least 1 day before)
curl -H "Accept-Encoding: br, gzip" "https://api.gridstatus.io/v1/datasets/ercot_load_forecast/query?publish_time=latest_before:-1 day&start_time=2026-01-01&end_time=2026-01-02&api_key=YOUR_API_KEY"
```

{% endcode %}

{% code title="Python" %}

```python
import gridstatusio as gs

client = gs.GridStatusClient(api_key="YOUR_API_KEY")

# Get the most recent forecast for each hour
df = client.get_dataset(
    "ercot_load_forecast",
    start="2026-01-01",
    end="2026-01-02",
    publish_time="latest",
)

# Get day-ahead forecasts (published at least 1 day before)
df = client.get_dataset(
    "ercot_load_forecast",
    start="2026-01-01",
    end="2026-01-02",
    publish_time="latest_before:-1 day",
)
```

{% endcode %}

### `publish_time_start` / `publish_time_end`

Filter by publication time range. Cannot be used with `publish_time`.

| cURL Parameter       | Python Client Parameter | Type              | Description                          |
| -------------------- | ----------------------- | ----------------- | ------------------------------------ |
| `publish_time_start` | `publish_time_start`    | ISO 8601 datetime | Data published on or after this time |
| `publish_time_end`   | `publish_time_end`      | ISO 8601 datetime | Data published before this time      |

{% code title="cURL" %}

```shell
# Get forecasts published on a specific day
curl -H "Accept-Encoding: br, gzip" "https://api.gridstatus.io/v1/datasets/ercot_load_forecast/query?publish_time_start=2026-01-01&publish_time_end=2026-01-02&api_key=YOUR_API_KEY"
```

{% endcode %}

{% code title="Python" %}

```python
import gridstatusio as gs

client = gs.GridStatusClient(api_key="YOUR_API_KEY")

# Get forecasts published on a specific day
df = client.get_dataset(
    "ercot_load_forecast",
    start="2026-01-01",
    end="2026-01-02",
    publish_time_start="2026-01-01",
    publish_time_end="2026-01-02",
)
```

{% endcode %}

## Column Filtering

Filter rows by column values.

| cURL Parameter    | Python Client Parameter | Type                 | Description                        |
| ----------------- | ----------------------- | -------------------- | ---------------------------------- |
| `filter_column`   | `filter_column`         | string               | Column name to filter on           |
| `filter_value`    | `filter_value`          | string, int, or list | Value(s) to match                  |
| `filter_operator` | `filter_operator`       | string               | Comparison operator (default: `=`) |

### `filter_operator` Values

| Operator | Description                           |
| -------- | ------------------------------------- |
| `=`      | Equals (default)                      |
| `!=`     | Not equals                            |
| `>`      | Greater than                          |
| `>=`     | Greater than or equal                 |
| `<`      | Less than                             |
| `<=`     | Less than or equal                    |
| `in`     | Matches any of comma-separated values |

**Note:** When using the `in` operator with cURL, pass comma-separated values. In the Python client, pass a list.

{% code title="cURL" %}

```shell
# Single value
curl -H "Accept-Encoding: br, gzip" "https://api.gridstatus.io/v1/datasets/ercot_lmp_by_settlement_point/query?filter_column=location&filter_value=HB_HOUSTON&start_time=2026-01-01&end_time=2026-01-02&api_key=YOUR_API_KEY"

# Multiple values
curl -H "Accept-Encoding: br, gzip" "https://api.gridstatus.io/v1/datasets/ercot_lmp_by_settlement_point/query?filter_column=location&filter_value=HB_HOUSTON,HB_NORTH&filter_operator=in&start_time=2026-01-01&end_time=2026-01-02&api_key=YOUR_API_KEY"

# Numeric threshold
curl -H "Accept-Encoding: br, gzip" "https://api.gridstatus.io/v1/datasets/ercot_lmp_by_settlement_point/query?filter_column=lmp&filter_value=100&filter_operator=>&start_time=2026-01-01&end_time=2026-01-02&api_key=YOUR_API_KEY"
```

{% endcode %}

{% code title="Python" %}

```python
import gridstatusio as gs

client = gs.GridStatusClient(api_key="YOUR_API_KEY")

# Single value
df = client.get_dataset(
    "ercot_lmp_by_settlement_point",
    start="2026-01-01",
    end="2026-01-02",
    filter_column="location",
    filter_value="HB_HOUSTON",
)

# Multiple values (use a list with filter_operator="in")
df = client.get_dataset(
    "ercot_lmp_by_settlement_point",
    start="2026-01-01",
    end="2026-01-02",
    filter_column="location",
    filter_value=["HB_HOUSTON", "HB_NORTH"],
    filter_operator="in",
)

# Numeric threshold
df = client.get_dataset(
    "ercot_lmp_by_settlement_point",
    start="2026-01-01",
    end="2026-01-02",
    filter_column="lmp",
    filter_value=100,
    filter_operator=">",
)
```

{% endcode %}

## Column Selection

### `columns`

Select specific columns to return. Reduces response size.

| cURL Parameter | Python Client Parameter | Type                           | Description       |
| -------------- | ----------------------- | ------------------------------ | ----------------- |
| `columns`      | `columns`               | comma-separated string or list | Columns to return |

**Note:** In cURL, pass columns as a comma-separated string. In the Python client, pass a list of column names.

{% code title="cURL" %}

```shell
curl -H "Accept-Encoding: br, gzip" "https://api.gridstatus.io/v1/datasets/ercot_lmp_by_settlement_point/query?columns=interval_start_utc,location,lmp&start_time=2026-01-01&end_time=2026-01-02&filter_column=location&filter_value=HB_HOUSTON&api_key=YOUR_API_KEY"
```

{% endcode %}

{% code title="Python" %}

```python
import gridstatusio as gs

client = gs.GridStatusClient(api_key="YOUR_API_KEY")

df = client.get_dataset(
    "ercot_lmp_by_settlement_point",
    start="2026-01-01",
    end="2026-01-02",
    columns=["interval_start_utc", "location", "lmp"],
    filter_column="location",
    filter_value="HB_HOUSTON",
)
```

{% endcode %}

## Resampling

Aggregate data to different time frequencies. Requires `start_time` and `end_time` (or `start` and `end` in Python).

| cURL Parameter       | Python Client Parameter | Type           | Description                          |
| -------------------- | ----------------------- | -------------- | ------------------------------------ |
| `resample_frequency` | `resample`              | string         | Time frequency to aggregate to       |
| `resample_function`  | `resample_function`     | string         | Aggregation function (default: mean) |
| `resample_by`        | `resample_by`           | string or list | Columns to group by when resampling  |

### `resample_frequency` / `resample` Values

| Value        | Description         |
| ------------ | ------------------- |
| `1 minute`   | 1-minute intervals  |
| `5 minutes`  | 5-minute intervals  |
| `10 minutes` | 10-minute intervals |
| `15 minutes` | 15-minute intervals |
| `1 hour`     | Hourly              |
| `1 day`      | Daily               |
| `1 week`     | Weekly              |
| `1 month`    | Monthly             |
| `1 year`     | Yearly              |

**Note:** For cURL, URL-encode spaces as `%20` (e.g., `resample_frequency=1%20hour`). The Python client handles this automatically.

### `resample_function` Values

| Value      | Description          |
| ---------- | -------------------- |
| `mean`     | Average (default)    |
| `sum`      | Total                |
| `min`      | Minimum              |
| `max`      | Maximum              |
| `count`    | Count of data points |
| `stddev`   | Standard deviation   |
| `variance` | Variance             |

### `resample_by`

Columns to group by when resampling. By default, groups by time index and subseries index (if present).

| cURL Parameter | Python Client Parameter | Type                           | Description         |
| -------------- | ----------------------- | ------------------------------ | ------------------- |
| `resample_by`  | `resample_by`           | comma-separated string or list | Columns to group by |

{% code title="cURL" %}

```shell
# Hourly average prices
curl -H "Accept-Encoding: br, gzip" "https://api.gridstatus.io/v1/datasets/ercot_lmp_by_settlement_point/query?filter_column=location&filter_value=HB_HOUSTON&resample_frequency=1%20hour&resample_function=mean&start_time=2026-01-01&end_time=2026-01-02&api_key=YOUR_API_KEY"

# Daily peak load
curl -H "Accept-Encoding: br, gzip" "https://api.gridstatus.io/v1/datasets/ercot_load/query?resample_frequency=1%20day&resample_function=max&start_time=2026-01-01&end_time=2026-01-08&api_key=YOUR_API_KEY"

# Monthly generation totals
curl -H "Accept-Encoding: br, gzip" "https://api.gridstatus.io/v1/datasets/ercot_fuel_mix/query?resample_frequency=1%20month&resample_function=sum&start_time=2026-01-01&end_time=2026-02-01&api_key=YOUR_API_KEY"
```

{% endcode %}

{% code title="Python" %}

```python
import gridstatusio as gs

client = gs.GridStatusClient(api_key="YOUR_API_KEY")

# Hourly average prices
df = client.get_dataset(
    "ercot_lmp_by_settlement_point",
    start="2026-01-01",
    end="2026-01-02",
    filter_column="location",
    filter_value="HB_HOUSTON",
    resample="1 hour",
    resample_function="mean",
)

# Daily peak load
df = client.get_dataset(
    "ercot_load",
    start="2026-01-01",
    end="2026-01-08",
    resample="1 day",
    resample_function="max",
)

# Monthly generation totals
df = client.get_dataset(
    "ercot_fuel_mix",
    start="2026-01-01",
    end="2026-02-01",
    resample="1 month",
    resample_function="sum",
)
```

{% endcode %}

## Timezone

### `timezone`

Convert timestamps to a specific timezone. Returns both UTC and local columns.

| cURL Parameter | Python Client Parameter | Type   | Description                                 |
| -------------- | ----------------------- | ------ | ------------------------------------------- |
| `timezone`     | `timezone`              | string | IANA timezone, `market`, or `UTC` (default) |

### Timezone Values

| Value         | Description                                 |
| ------------- | ------------------------------------------- |
| IANA timezone | e.g., `America/Chicago`, `America/New_York` |
| `market`      | Auto-detect from dataset's source ISO       |
| `UTC`         | UTC (default)                               |

Common timezones:

| ISO                | Timezone           |
| ------------------ | ------------------ |
| CAISO              | `US/Pacific`       |
| ERCOT, SPP         | `US/Central`       |
| IESO, MISO         | `EST` (year-round) |
| ISO-NE, NYISO, PJM | `US/Eastern`       |

{% code title="cURL" %}

```shell
curl -H "Accept-Encoding: br, gzip" "https://api.gridstatus.io/v1/datasets/ercot_fuel_mix/query?timezone=America/Chicago&start_time=2026-01-01&end_time=2026-01-02&limit=5&api_key=YOUR_API_KEY"
```

{% endcode %}

{% code title="Python" %}

```python
import gridstatusio as gs

client = gs.GridStatusClient(api_key="YOUR_API_KEY")

df = client.get_dataset(
    "ercot_fuel_mix",
    start="2026-01-01",
    end="2026-01-02",
    timezone="America/Chicago",
    limit=5,
)
# DataFrame includes both interval_start_utc and interval_start_local columns
```

{% endcode %}

Response adds local time columns:

{% code title="JSON" %}

```json
{
    "interval_start_local": "2025-12-31T18:00:00-06:00",
    "interval_start_utc": "2026-01-01T00:00:00+00:00"
}
```

{% endcode %}

## Pagination

The API supports both cursor and offset based pagination. For more, see [Pagination documentation](https://docs.gridstatus.io/developers/concepts/pagination).

| cURL Parameter | Python Client Parameter | Type        | Description                                            |
| -------------- | ----------------------- | ----------- | ------------------------------------------------------ |
| `limit`        | `limit`                 | int         | Maximum total rows to return across all pages          |
| `page_size`    | `page_size`             | int         | Rows per page. Maximum varies by subscription plan     |
| `page`         | *(handled internally)*  | int         | Page number for offset-based pagination (starts at 1)  |
| `cursor`       | `use_cursor_pagination` | string/bool | Cursor for pagination or boolean to enable cursor mode |

**Note:** The Python client handles pagination automatically. Set `use_cursor_pagination=True` (default) for efficient cursor-based pagination, or `False` for page-based pagination.

{% code title="cURL" %}

```shell
# First request
curl -H "Accept-Encoding: br, gzip" "https://api.gridstatus.io/v1/datasets/ercot_fuel_mix/query?page_size=1000&start_time=2026-01-01&end_time=2026-01-02&api_key=YOUR_API_KEY"

# Response includes cursor for next page

# Use cursor for subsequent requests
curl -H "Accept-Encoding: br, gzip" "https://api.gridstatus.io/v1/datasets/ercot_fuel_mix/query?cursor=CURSOR_FROM_RESPONSE&api_key=YOUR_API_KEY"
```

{% endcode %}

{% code title="Python" %}

```python
import gridstatusio as gs

client = gs.GridStatusClient(api_key="YOUR_API_KEY")

# Client handles pagination automatically
# Set limit to control total rows returned
df = client.get_dataset(
    "ercot_fuel_mix",
    start="2026-01-01",
    end="2026-01-02",
    limit=1000,  # Maximum rows to return
    page_size=500,  # Rows per API request
    use_cursor_pagination=True,  # Use cursor pagination (default)
)
```

{% endcode %}

## Sorting

### `order`

| cURL Parameter | Python Client Parameter | Value  | Description                       |
| -------------- | ----------------------- | ------ | --------------------------------- |
| `order`        | *(not available)*       | `asc`  | Ascending, oldest first (default) |
| `order`        | *(not available)*       | `desc` | Descending, newest first          |

**Note:** The `order` parameter is only available via the direct API (cURL). The Python client returns data in ascending order by default. To get the newest data first, you can sort the resulting DataFrame in Python.

{% code title="cURL" %}

```shell
curl -H "Accept-Encoding: br, gzip" "https://api.gridstatus.io/v1/datasets/ercot_fuel_mix/query?order=desc&limit=10&api_key=YOUR_API_KEY"
```

{% endcode %}

{% code title="Python" %}

```python
import gridstatusio as gs

client = gs.GridStatusClient(api_key="YOUR_API_KEY")

# Get data (returns in ascending order)
df = client.get_dataset(
    "ercot_fuel_mix",
    start="2026-01-01",
    end="2026-01-02",
    limit=10,
)

# Sort descending in pandas if needed
df = df.sort_values("interval_start_utc", ascending=False)
```

{% endcode %}

## Response Format

| cURL Parameter  | Python Client Parameter | Type   | Description                              |
| --------------- | ----------------------- | ------ | ---------------------------------------- |
| `return_format` | `request_format`\*      | string | Response format: `json` (default), `csv` |
| `json_schema`   | *(set automatically)*   | string | JSON structure                           |
| `download`      | *(not available)*       | bool   | Return as downloadable file              |

\*Set `request_format` in the client constructor, not per request.

### `return_format` Values

| Value  | Description             |
| ------ | ----------------------- |
| `json` | JSON response (default) |
| `csv`  | CSV response            |

### `json_schema` Values

Structure of JSON response.

| Value              | Description                                 |
| ------------------ | ------------------------------------------- |
| `array-of-objects` | `[{col1: val1, col2: val2}, ...]` (default) |
| `array-of-arrays`  | `[[val1, val2], ...]` (more compact)        |

**Note:** The Python client automatically uses `array-of-arrays` for efficiency.

### `download`

Set to `true` to return as downloadable file attachment (cURL only).

{% code title="cURL" %}

```shell
# Download as CSV
curl -H "Accept-Encoding: br, gzip" "https://api.gridstatus.io/v1/datasets/ercot_fuel_mix/query?return_format=csv&start_time=2026-01-01&end_time=2026-01-02&api_key=YOUR_API_KEY" -o data.csv
```

{% endcode %}

{% code title="Python" %}

```python
import gridstatusio as gs

# Set request format in constructor
client = gs.GridStatusClient(
    api_key="YOUR_API_KEY",
    request_format="csv",  # or "json" (default)
)

df = client.get_dataset(
    "ercot_fuel_mix",
    start="2026-01-01",
    end="2026-01-02",
)

# Save to CSV locally
df.to_csv("data.csv", index=False)
```

{% endcode %}

## Complete Example

Combining multiple parameters:

{% code title="cURL" %}

```shell
curl -H "Accept-Encoding: br, gzip" "https://api.gridstatus.io/v1/datasets/ercot_lmp_by_settlement_point/query?\
start_time=2026-01-01&\
end_time=2026-01-02&\
filter_column=location&\
filter_value=HB_HOUSTON,HB_NORTH&\
filter_operator=in&\
columns=interval_start_utc,location,lmp&\
resample_frequency=1%20hour&\
resample_function=mean&\
timezone=America/Chicago&\
order=desc&\
api_key=YOUR_API_KEY"
```

{% endcode %}

{% code title="Python" %}

```python
import gridstatusio as gs

client = gs.GridStatusClient(api_key="YOUR_API_KEY")

df = client.get_dataset(
    "ercot_lmp_by_settlement_point",
    start="2026-01-01",
    end="2026-01-02",
    filter_column="location",
    filter_value=["HB_HOUSTON", "HB_NORTH"],  # List of values for "in" operator
    filter_operator="in",
    columns=["interval_start_utc", "location", "lmp"],
    resample="1 hour",
    resample_function="mean",
    timezone="America/Chicago",
)

# Sort descending if needed (Python client returns ascending by default)
df = df.sort_values("interval_start_utc", ascending=False)
```

{% endcode %}

## Parameter Reference Summary

| cURL Parameter       | Python Client Parameter | Notes                                          |
| -------------------- | ----------------------- | ---------------------------------------------- |
| `start_time`         | `start`                 | ISO 8601 datetime                              |
| `end_time`           | `end`                   | ISO 8601 datetime                              |
| `time`               | *(not available)*       | Use `start`/`end` with `limit=1` in Python     |
| `time_comparison`    | *(not available)*       | cURL only                                      |
| `publish_time`       | `publish_time`          | Same values                                    |
| `publish_time_start` | `publish_time_start`    | ISO 8601 datetime                              |
| `publish_time_end`   | `publish_time_end`      | ISO 8601 datetime                              |
| `filter_column`      | `filter_column`         | Same                                           |
| `filter_value`       | `filter_value`          | cURL: comma-separated, Python: string/int/list |
| `filter_operator`    | `filter_operator`       | Same values                                    |
| `columns`            | `columns`               | cURL: comma-separated, Python: list            |
| `resample_frequency` | `resample`              | Same values (e.g., "1 hour")                   |
| `resample_function`  | `resample_function`     | Same values                                    |
| `resample_by`        | `resample_by`           | cURL: comma-separated, Python: string/list     |
| `timezone`           | `timezone`              | Same values                                    |
| `limit`              | `limit`                 | Same                                           |
| `page_size`          | `page_size`             | Same                                           |
| `page`               | *(handled internally)*  | Python client handles pagination               |
| `cursor`             | `use_cursor_pagination` | Python: boolean to enable                      |
| `order`              | *(not available)*       | Sort DataFrame in Python                       |
| `return_format`      | `request_format`\*      | Set in constructor                             |
| `json_schema`        | *(set automatically)*   | Python client uses array-of-arrays             |
| `download`           | *(not available)*       | Use `df.to_csv()` in Python                    |


# Best Practices

Optimize your Grid Status API usage for performance, reliability, and cost-effectiveness.

## Query Optimization

{% stepper %}
{% step %}

### Always Use Time Filters

Unbounded queries can be slow and expensive. Always specify `start_time` and `end_time` when querying time-series data.

{% tabs %}
{% tab title="Bad" %}

```shell
# Queries entire dataset - slow and expensive
curl -H "Accept-Encoding: br, gzip" "https://api.gridstatus.io/v1/datasets/ercot_lmp_by_settlement_point/query?api_key=YOUR_API_KEY"
```

{% endtab %}

{% tab title="Good" %}

```shell
# Bounded time range with location filter - fast and efficient
curl -H "Accept-Encoding: br, gzip" "https://api.gridstatus.io/v1/datasets/ercot_lmp_by_settlement_point/query?\
start_time=2026-01-01&\
end_time=2026-01-02&\
filter_column=location&\
filter_value=HB_HOUSTON&\
api_key=YOUR_API_KEY"
```

{% endtab %}
{% endtabs %}
{% endstep %}

{% step %}

### Filter by Subseries

Most LMP and load datasets contain data for many locations. Filter to the specific locations you need.

Why this matters: LMP datasets like `pjm_lmp_real_time_5_min` contain 10,000+ pricing nodes. Querying all nodes for a single day can return millions of rows. If you only need hub prices for trading decisions, filter to those specific hubs.

{% tabs %}
{% tab title="Bad" %}

```shell
# Returns data for all 10,000+ nodes
curl -H "Accept-Encoding: br, gzip" "https://api.gridstatus.io/v1/datasets/pjm_lmp_real_time_5_min/query?api_key=YOUR_API_KEY"
```

{% endtab %}

{% tab title="Good" %}

```shell
# Returns data for one specific hub
curl -H "Accept-Encoding: br, gzip" "https://api.gridstatus.io/v1/datasets/pjm_lmp_real_time_5_min/query?\
start_time=2026-01-01&\
end_time=2026-01-02&\
filter_column=location&\
filter_value=WESTERN%20HUB&\
api_key=YOUR_API_KEY"
```

{% endtab %}
{% endtabs %}
{% endstep %}

{% step %}

### Select Only Needed Columns

Reduce response size by requesting only the columns you need.

{% tabs %}
{% tab title="Shell" %}

```shell
# Only get timestamp, location, and LMP
curl -H "Accept-Encoding: br, gzip" "https://api.gridstatus.io/v1/datasets/caiso_lmp_real_time_5_min/query?\
start_time=2026-01-01&\
end_time=2026-01-02&\
columns=interval_start_utc,location,lmp&\
filter_column=location&\
filter_value=TH_SP15_GEN-APND&\
api_key=YOUR_API_KEY"
```

{% endtab %}

{% tab title="Python" %}

```python
# Only get timestamp, location, and LMP - skip energy, congestion, loss components
df = client.get_dataset(
    "caiso_lmp_real_time_5_min",
    start="2026-01-01",
    end="2026-01-02",
    columns=["interval_start_utc", "location", "lmp"],
    filter_column="location",
    filter_value="TH_SP15_GEN-APND"
)

# Response is ~60% smaller than without column selection
```

{% endtab %}
{% endtabs %}
{% endstep %}

{% step %}

### Request Compressed Responses

The API compresses responses with **brotli** or **gzip** whenever your client advertises support through the `Accept-Encoding` request header. For large dataset queries this shrinks the transfer by up to \~20x — a 60 MB JSON response drops to roughly 3 MB — which means faster downloads, lower bandwidth costs, and fewer timeouts.

Most HTTP clients request compression automatically, including the Grid Status Python client, `requests`, `httpx`, and web browsers. Set the header explicitly if your integration — for example, some ETL platforms or no-code HTTP connectors — does not send it by default.

{% tabs %}
{% tab title="Shell" %}

```shell
# Send Accept-Encoding to receive a compressed response (brotli preferred, gzip fallback).
# curl --compressed sets this header and decompresses the response for you automatically.
curl -H "Accept-Encoding: br, gzip" "https://api.gridstatus.io/v1/datasets/ercot_lmp_by_settlement_point/query?\
start_time=2026-01-01&\
end_time=2026-01-02&\
filter_column=location&\
filter_value=HB_HOUSTON&\
limit=100&\
api_key=YOUR_API_KEY"
```

{% endtab %}

{% tab title="Python" %}

```python
# The Grid Status Python client requests compression automatically - no action needed.
# requests and httpx also send Accept-Encoding and decompress responses by default.
df = client.get_dataset(
    "ercot_lmp_by_settlement_point",
    start="2026-01-01",
    end="2026-01-02",
    filter_column="location",
    filter_value="HB_HOUSTON",
    limit=100,
)
```

{% endtab %}
{% endtabs %}
{% endstep %}

{% step %}

### Use Appropriate Limits

Set explicit limits to control data volume and costs.

{% tabs %}
{% tab title="Python" %}

```python
# Always set a limit during development
data = client.get_dataset(
    "ercot_fuel_mix",
    start="2026-01-01",
    end="2026-01-02",
    limit=1000  # Prevent accidental large queries
)
```

{% endtab %}
{% endtabs %}
{% endstep %}

{% step %}

### Resample Locally

If a query involving resampling is timing out on the API, download the raw data and perform resampling locally.
{% endstep %}
{% endstepper %}

## Pagination Strategies

### Use Cursor Pagination for Large Datasets

Cursor-based pagination is more efficient than offset-based for large result sets. The client handles this automatically. For more see [Pagination documentation.](https://docs.gridstatus.io/developers/concepts/pagination)

{% tabs %}
{% tab title="Python" %}

```python
# The client handles pagination automatically - no manual cursor management needed
df = client.get_dataset(
    "ercot_fuel_mix",
    start="2026-01-01",
    end="2026-01-02"
)

# All pages are fetched and combined into a single DataFrame
print(f"Retrieved {len(df)} total rows")
```

{% endtab %}
{% endtabs %}

### Batch Large Date Ranges

For queries spanning months or years, batch into smaller chunks.

{% tabs %}
{% tab title="Python" %}

```python
import pandas as pd
from datetime import datetime, timedelta

def fetch_in_batches(
    client,
    dataset: str,
    start: datetime,
    end: datetime,
    batch_days: int = 7,
    **kwargs
) -> pd.DataFrame:
    """Fetch data in batches to avoid timeouts."""
    all_data = []
    current = start

    while current < end:
        batch_end = min(current + timedelta(days=batch_days), end)

        print(f"Fetching {current.date()} to {batch_end.date()}...")

        data = client.get_dataset(
            dataset,
            start=current.isoformat(),
            end=batch_end.isoformat(),
            **kwargs
        )

        if len(data) > 0:
            all_data.append(data)

        current = batch_end

    return pd.concat(all_data, ignore_index=True) if all_data else pd.DataFrame()

# Usage
df = fetch_in_batches(
    client,
    "ercot_fuel_mix",
    datetime(2026, 1, 1),
    datetime(2026, 2, 1),
    batch_days=7
)
```

{% endtab %}
{% endtabs %}

## Error Handling

### Implement Retry Logic

Handle transient errors gracefully with exponential backoff.

{% tabs %}
{% tab title="Python" %}

```python
# The client handles retries automatically with exponential backoff

# Configure retry behavior when creating the client:
retry_client = gs.GridStatusClient(
    api_key="YOUR_API_KEY",
    max_retries=5,      # Retry up to 5 times
    base_delay=2.0,     # Start with 2 second delay
    exponential_base=2  # Double delay each retry
)

# All queries will automatically retry on transient errors (429, 500, 502, 503, 504)
df = retry_client.get_dataset("ercot_fuel_mix", start="2026-01-01", end="2026-01-02")
```

{% endtab %}
{% endtabs %}

### Monitor API Usage

Check usage before large operations to avoid hitting limits.

{% tabs %}
{% tab title="Python" %}

```python
def safe_query(client, dataset: str, expected_rows: int, **kwargs):
    """Check quota before querying."""
    usage = client.get_api_usage()

    rows_used = usage['current_period_usage']['total_api_rows_returned']
    rows_limit = usage['limits']['api_rows_returned_limit']
    rows_remaining = rows_limit - rows_used

    if rows_remaining < expected_rows:
        raise Exception(
            f"Insufficient quota: need ~{expected_rows:,}, "
            f"have {rows_remaining:,}"
        )

    return client.get_dataset(dataset, **kwargs)

# Usage
try:
    # Estimate: 288 5-min intervals/day * 1 location = ~288 rows
    df = safe_query(
        client,
        "ercot_fuel_mix",
        expected_rows=500,
        start="2026-01-01",
        end="2026-01-02"
    )
except Exception as e:
    print(f"Cannot proceed: {e}")
```

{% endtab %}
{% endtabs %}

## Data Quality

Data quality checks are critical for energy trading and operational applications where decisions are time-sensitive.

### Verify Data Freshness

Check that data is current before using it in production.

Use case: Before executing trades based on current prices, verify the data is within an acceptable age threshold. Stale data could lead to trading on outdated price signals.

{% tabs %}
{% tab title="Python" %}

```python
from datetime import datetime, timezone, timedelta

def check_data_freshness(dataset_id: str, max_age_minutes: int = 30):
    """Check if dataset data is fresh enough."""
    metadata = client.get(
            f"{client.host}/datasets/{dataset_id}",
            return_raw_response_json=True
         )

    latest = datetime.fromisoformat(
        metadata['latest_available_time_utc'].replace('Z', '+00:00')
    )
    now = datetime.now(timezone.utc)
    age = now - latest

    if age > timedelta(minutes=max_age_minutes):
        print(f"Warning: Data is {age.total_seconds()/60:.0f} minutes old")
        return False

    return True

# Usage
if check_data_freshness("ercot_fuel_mix"):
    print("Data is fresh - proceeding with analysis")
else:
    print("Data may be stale - check for issues")
```

{% endtab %}
{% endtabs %}

### Validate Query Results

Verify that returned data meets expectations.

{% tabs %}
{% tab title="Python" %}

```python
import pandas as pd

def validate_results(df: pd.DataFrame, expected_cols: list, time_col: str = None):
    """Basic validation of query results."""
    errors = []

    # Check for expected columns
    missing_cols = set(expected_cols) - set(df.columns)
    if missing_cols:
        errors.append(f"Missing columns: {missing_cols}")

    # Check for empty result
    if len(df) == 0:
        errors.append("No data returned")

    # Check for time continuity (if time column specified)
    if time_col and time_col in df.columns:
        df[time_col] = pd.to_datetime(df[time_col])
        gaps = df[time_col].diff().dropna()

        # Check for unexpected gaps (>2x median interval)
        median_gap = gaps.median()
        large_gaps = gaps[gaps > median_gap * 2]

        if len(large_gaps) > 0:
            errors.append(f"Found {len(large_gaps)} time gaps")

    if errors:
        print("Validation errors:", errors)
        return False

    return True

# Usage
df = client.get_dataset("ercot_fuel_mix", start="2026-01-01", end="2026-01-02")

if validate_results(df, ['interval_start_utc', 'solar', 'wind'], 'interval_start_utc'):
    print("Data validated successfully")
```

{% endtab %}
{% endtabs %}

## Performance Summary

| Practice             | Impact | Implementation                                                |
| -------------------- | ------ | ------------------------------------------------------------- |
| Use time filters     | High   | Always set `start_time` and `end_time`                        |
| Filter by location   | High   | Use `filter_column`/`filter_value`                            |
| Resampling           | High   | Remove resampling. Fetch raw data first and resample locally. |
| Batch large requests | High   | Split into smaller chunks                                     |
| Retry on errors      | High   | Implement exponential backoff (included in the client)        |
| Compress responses   | High   | Send `Accept-Encoding: br, gzip` (automatic in most clients)  |
| Select columns       | Medium | Use `columns` parameter                                       |
| Cursor pagination    | Medium | Use `cursor` instead of `page`                                |
| Monitor usage        | Medium | Check quota before large queries                              |

## Related Documentation

* [Advanced Query Features](file:///docs/api/advanced-query-features) - Filtering, resampling, timezone
* [Error Handling](file:///docs/api/error-handling) - Handle errors gracefully
* [Utility Endpoints](file:///docs/api/utility-endpoints) - API usage, metadata, column values


# Error Handling

Understanding API error responses and how to handle them effectively in your applications.

## Overview

The Grid Status API uses standard HTTP status codes to indicate the success or failure of requests. Error responses include a JSON body with details about what went wrong.

## Error Response Format

All error responses follow this structure:

```json
{
    "detail": "Human-readable error message describing what went wrong."
}
```

## HTTP Status Codes

### Success Codes

| Code | Description       |
| ---- | ----------------- |
| 200  | Request succeeded |

### Client Error Codes (4xx)

| Code | Name                 | Description                                |
| ---- | -------------------- | ------------------------------------------ |
| 400  | Bad Request          | Invalid parameters or malformed request    |
| 401  | Unauthorized         | Missing or invalid API key                 |
| 403  | Forbidden            | Valid API key but insufficient permissions |
| 404  | Not Found            | Resource (dataset, column, etc.) not found |
| 422  | Unprocessable Entity | Query timeout or validation error          |
| 429  | Too Many Requests    | Rate limit or usage limit exceeded         |

### Server Error Codes (5xx)

| Code | Name                  | Description                    |
| ---- | --------------------- | ------------------------------ |
| 500  | Internal Server Error | Unexpected server error        |
| 502  | Bad Gateway           | Upstream service unavailable   |
| 503  | Service Unavailable   | Server temporarily unavailable |
| 504  | Gateway Timeout       | Request took too long          |

***

## Common Errors and Solutions

### 401 Unauthorized

**Cause:** Missing or invalid API key.

```json
{
    "detail": "API key is required."
}
```

**Solutions:**

* Verify your API key is correct
* Check that the API key is being passed correctly (header or query parameter)
* Ensure the API key hasn't been revoked

{% tabs %}
{% tab title="Shell" %}

```shell
# Correct: API key as query parameter
curl -H "Accept-Encoding: br, gzip" "https://api.gridstatus.io/v1/datasets?api_key=YOUR_API_KEY"

# Correct: API key as header
curl -H "Accept-Encoding: br, gzip" -H "x-api-key: YOUR_API_KEY" "https://api.gridstatus.io/v1/datasets"
```

{% endtab %}

{% tab title="Python" %}

```python
import gridstatusio as gs

# Ensure API key is set
client = gs.GridStatusClient(api_key="YOUR_API_KEY")

# Or via environment variable

# export GRIDSTATUS_API_KEY=your_api_key
client = gs.GridStatusClient()
```

{% endtab %}
{% endtabs %}

***

### 403 Forbidden

**Cause:** Your subscription doesn't include access to the requested resource or feature.

```json
{
    "detail": "Access to this dataset requires a paid subscription."
}
```

**Common scenarios:**

* Accessing a premium dataset on a free plan
* Using resampling without a paid subscription
* Accessing audit data without proper entitlements

**Solutions:**

* Upgrade your subscription plan
* Check which datasets are available on your plan
* Contact support if you believe you should have access

***

### 404 Not Found

**Cause:** The requested resource doesn't exist.

**Dataset not found:**

```json
{
    "detail": "Dataset invalid_dataset_id not found."
}
```

**Column not found:**

```json
{
    "detail": "Column not found."
}
```

**Solutions:**

* Verify the dataset ID is spelled correctly
* Use the list datasets endpoint to see available datasets
* Check that the column name exists using the dataset metadata endpoint

{% tabs %}
{% tab title="Shell" %}

```shell
# List available datasets
curl -H "Accept-Encoding: br, gzip" "https://api.gridstatus.io/v1/datasets?api_key=YOUR_API_KEY" | jq '.data[].id'

# Check columns in a dataset
curl -H "Accept-Encoding: br, gzip" "https://api.gridstatus.io/v1/datasets/ercot_fuel_mix?api_key=YOUR_API_KEY" | jq '.all_columns[].name'
```

{% endtab %}

{% tab title="Python" %}

```python
# List available datasets
datasets = client.list_datasets(return_list=True)
print([d['id'] for d in datasets])

# Get metadata for a specific dataset to see columns
metadata = client.get(
    f"{client.host}/datasets/ercot_fuel_mix",
    return_raw_response_json=True
)
columns = [col['name'] for col in metadata['all_columns']]
print(f"Available columns: {columns}")
```

{% endtab %}
{% endtabs %}

***

### 422 Unprocessable Entity - Query Timeout

**Cause:** The query took too long to execute and was cancelled.

```json
{
    "detail": "Query timed out. The following may allow the query to complete within the timeout: Reduce the time range of the query. Remove resampling. Use '=' instead of other comparison operators in filters. Set a limit on the number of rows returned. If none of these options work for you our Snowflake offering may meet your needs. Please contact us at contact@gridstatus.io for more information."
}
```

**Solutions:**

{% stepper %}
{% step %}

### Reduce time range

Example: Instead of querying all locations, filter to the specific location you need.

{% tabs %}
{% tab title="Shell" %}

```shell
curl -H "Accept-Encoding: br, gzip" "https://api.gridstatus.io/v1/datasets/caiso_lmp_real_time_5_min/query?\
start_time=2026-01-01&\
end_time=2026-01-02&\
filter_column=location&\
filter_value=TH_SP15_GEN-APND&\
api_key=YOUR_API_KEY"
```

{% endtab %}
{% endtabs %}
{% endstep %}

{% step %}

### Add filters

Filter to specific locations instead of all locations.

{% tabs %}
{% tab title="Shell" %}

```shell
curl -H "Accept-Encoding: br, gzip" "https://api.gridstatus.io/v1/datasets/ercot_lmp_by_settlement_point/query?\
start_time=2026-01-01&\
end_time=2026-01-02&\
filter_column=location&\
filter_value=HB_HOUSTON&\
api_key=YOUR_API_KEY"
```

{% endtab %}
{% endtabs %}
{% endstep %}

{% step %}

### Set a limit

Limit the number of rows returned.

{% tabs %}
{% tab title="Shell" %}

```shell
curl -H "Accept-Encoding: br, gzip" "https://api.gridstatus.io/v1/datasets/pjm_lmp_real_time_5_min/query?\
start_time=2026-01-01&\
limit=100&\
api_key=YOUR_API_KEY"
```

{% endtab %}
{% endtabs %}
{% endstep %}

{% step %}

### Remove resampling

Server-side resampling can be expensive. Consider downloading raw data and resampling client-side.
{% endstep %}
{% endstepper %}

***

### 429 Too Many Requests

**Cause:** You've exceeded rate limits or monthly usage limits.

**Rate limit exceeded:**

```json
{
    "detail": "Rate limit exceeded. Try again in 60 seconds."
}
```

**Monthly limit exceeded:**

```json
{
    "detail": "Monthly row limit exceeded. Limit resets on 2026-02-01."
}
```

**Solutions:**

* Implement exponential backoff

{% tabs %}
{% tab title="Python" %}

```python
# Configure the client with retry settings
retry_client = gs.GridStatusClient(
    api_key="YOUR_API_KEY",
    max_retries=5,      # Retry up to 5 times
    base_delay=2.0      # Start with 2 second delay
)

# Queries will automatically retry on 429 errors
df = retry_client.get_dataset("ercot_fuel_mix", start="2026-01-01", end="2026-01-02")
```

{% endtab %}
{% endtabs %}

* Check usage before large queries

{% tabs %}
{% tab title="Python" %}

```python

usage = client.get_api_usage()

rows_used = usage['current_period_usage']['total_api_rows_returned']
rows_limit = usage['limits']['api_rows_returned_limit']
rows_remaining = rows_limit - rows_used

if rows_remaining < 10000:
    print("Warning: Low quota remaining!")
```

{% endtab %}
{% endtabs %}

* Upgrade your plan if you consistently hit limits.

***

### 400 Bad Request

**Cause:** Invalid parameter values or missing required parameters.

**Invalid column:**

```json
{
    "detail": "Column invalid_column not found in dataset. Possible columns: ['interval_start_utc', 'location', 'lmp']."
}
```

**Invalid filter type:**

```json
{
    "detail": "Invalid type for filter_value, expected <class 'float'>."
}
```

**Invalid resample frequency:**

```json
{
    "detail": "Invalid resample_frequency: '2h'. Must be one of: 5min, 15min, 30min, 1h, 1d, 1w, 1M."
}
```

**Solutions:**

* Check the error message for valid options
* Use the dataset metadata endpoint to verify column names
* Review the query parameters documentation

***

## Error Handling Best Practices

{% stepper %}
{% step %}

### Use Try/Except with the Client

{% tabs %}
{% tab title="Python" %}

```python
try:
    df = client.get_dataset("ercot_fuel_mix", limit=10)
    print(f"Success: {len(df)} rows")
except Exception as e:
    print(f"Error: {e}")
```

{% endtab %}
{% endtabs %}
{% endstep %}

{% step %}

### Implement Retry Logic

{% tabs %}
{% tab title="Python" %}

```python
# Configure the client with built-in retry logic
retry_client = gs.GridStatusClient(
    api_key="YOUR_API_KEY",
    max_retries=3,       # Number of retries
    base_delay=2.0,      # Initial delay in seconds
    exponential_base=2   # Multiply delay by this each retry
)

# All queries will automatically retry on transient errors (429, 500, 502, 503, 504)
df = retry_client.get_dataset("ercot_fuel_mix", limit=10)
```

{% endtab %}
{% endtabs %}
{% endstep %}

{% step %}

### Log Errors for Debugging

{% tabs %}
{% tab title="Python" %}

```python
import logging

logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)

def query_with_logging(dataset: str, **kwargs) -> pd.DataFrame | None:
    try:
        df = client.get_dataset(dataset, **kwargs)
        logger.info(f"Query successful: {dataset}, {len(df)} rows returned")
        return df
    except Exception as e:
        logger.error(f"Query failed: {dataset}\nParams: {kwargs}\nError: {e}")
        return None

# Usage
df = query_with_logging("ercot_fuel_mix", start="2026-01-01", end="2026-01-02")
```

{% endtab %}
{% endtabs %}
{% endstep %}

{% step %}

### Handle Pagination Automatically

{% tabs %}
{% tab title="Python" %}

```python
# The client handles pagination automatically

# Just specify your query parameters and it fetches all pages
df = client.get_dataset(
    "ercot_fuel_mix",
    start="2026-01-01",
    end="2026-01-08"  # Large date range - client paginates automatically
)

print(f"Retrieved {len(df)} total rows across all pages")
```

{% endtab %}
{% endtabs %}
{% endstep %}
{% endstepper %}

## Related Documentation

* [Utility Endpoints](file:///docs/api/utility-endpoints) - Monitor your usage to avoid limits
* [Advanced Query Features](file:///docs/api/advanced-query-features) - Valid parameter values
* [Best Practices](file:///docs/api/best-practices) - Optimize queries to avoid timeouts


# Utility Endpoints

Additional endpoints for metadata, monitoring, and discovery.

## API Usage

```
GET /v1/api_usage
```

Monitor your consumption against subscription limits.

**Response Fields:**

| Field                                          | Description              |
| ---------------------------------------------- | ------------------------ |
| `plan_name`                                    | Your subscription plan   |
| `limits.api_rows_returned_limit`               | Max rows per month       |
| `limits.api_rows_per_response_limit`           | Max rows per response    |
| `current_period_usage.total_api_rows_returned` | Rows used this month     |
| `current_period_usage.total_requests`          | Requests made this month |

**Example:**

{% tabs %}
{% tab title="Shell" %}

```shell
curl -H "Accept-Encoding: br, gzip" "https://api.gridstatus.io/v1/api_usage?api_key=YOUR_API_KEY"
```

{% endtab %}

{% tab title="Python" %}

```python
usage = client.get_api_usage()
rows_used = usage['current_period_usage']['total_api_rows_returned']
rows_limit = usage['limits']['api_rows_returned_limit']
print(f"Rows used: {rows_used:,} / {rows_limit:,}")
```

{% endtab %}
{% endtabs %}

***

## Dataset Metadata

```
GET /v1/datasets/{dataset_id}
```

Get schema and availability information for a dataset.

**Response Fields:**

| Field                         | Description                          |
| ----------------------------- | ------------------------------------ |
| `id`                          | Dataset identifier                   |
| `name`                        | Human-readable name                  |
| `earliest_available_time_utc` | Start of data availability           |
| `latest_available_time_utc`   | Most recent data timestamp           |
| `time_index_column`           | Primary time column name             |
| `all_columns`                 | List of columns with types           |
| `data_frequency`              | Update interval (e.g., "5\_MINUTES") |

**Example:**

{% tabs %}
{% tab title="Shell" %}

```shell
curl -H "Accept-Encoding: br, gzip" "https://api.gridstatus.io/v1/datasets/ercot_fuel_mix?api_key=YOUR_API_KEY"
```

{% endtab %}

{% tab title="Python" %}

```python
metadata = client.get(
    f"{client.host}/datasets/ercot_fuel_mix",
    return_raw_response_json=True
)
print(f"Available: {metadata['earliest_available_time_utc']} to {metadata['latest_available_time_utc']}")
print(f"Columns: {[col['name'] for col in metadata['all_columns']]}")
```

{% endtab %}
{% endtabs %}

***

## Column Values

```
GET /v1/datasets/{dataset_id}/columns/{column}
```

Get unique values in a column. Useful for discovering filter options.

**Example:**

{% tabs %}
{% tab title="Shell" %}

```shell
curl -H "Accept-Encoding: br, gzip" "https://api.gridstatus.io/v1/datasets/ercot_lmp_by_settlement_point/columns/location?api_key=YOUR_API_KEY"
```

{% endtab %}

{% tab title="Python" %}

```python
result = client.get(
    f"{client.host}/datasets/ercot_lmp_by_settlement_point/columns/location",
    return_raw_response_json=True
)
hubs = [loc for loc in result['unique_values'] if loc.startswith('HB_')]
print(f"Hub locations: {hubs}")
```

{% endtab %}
{% endtabs %}

**Response:**

```json
{
    "column": "location",
    "type": "VARCHAR",
    "unique_values": ["HB_HOUSTON", "HB_NORTH", "HB_SOUTH", "HB_WEST", ...]
}
```

{% hint style="warning" %}
Results are based on the most recent 50,000 rows. Older values may not appear.
{% endhint %}

***

## Dataset Updates

```
GET /v1/dataset-updates/{dataset_id}
```

Track update history to monitor data freshness.

**Query Parameters:**

| Parameter | Default | Description           |
| --------- | ------- | --------------------- |
| `limit`   | None    | Max records to return |
| `order`   | `asc`   | Sort: `asc` or `desc` |

**Example:**

{% tabs %}
{% tab title="Shell" %}

```shell
curl -H "Accept-Encoding: br, gzip" "https://api.gridstatus.io/v1/dataset-updates/ercot_fuel_mix?order=desc&limit=5&api_key=YOUR_API_KEY"
```

{% endtab %}

{% tab title="Python" %}

```python
updates = client.get(
    f"{client.host}/dataset-updates/ercot_fuel_mix",
    params={"order": "desc", "limit": 5},
    return_raw_response_json=True
)
```

{% endtab %}
{% endtabs %}

**Response Fields:**

| Field               | Description                          |
| ------------------- | ------------------------------------ |
| `time_utc`          | When the update occurred             |
| `num_rows_inserted` | New rows added                       |
| `num_rows_updated`  | Existing rows modified               |
| `is_backfill`       | Whether this was historical backfill |

***

## Error Codes

| Code | Description                        |
| ---- | ---------------------------------- |
| 401  | Missing or invalid API key         |
| 403  | Dataset requires paid subscription |
| 404  | Dataset or column not found        |
| 429  | Rate limit exceeded                |


# Breaking Changes

What constitutes a breaking change to the Grid Status API, how we notify affected customers, and what to do when one affects you.

Occasionally, we make changes that are not backward compatible and require customers to update existing queries or integrations. This page describes what constitutes a breaking change, how we communicate those changes, and what you should do when one affects you.

## Why breaking changes happen

We avoid breaking changes whenever possible. When one is necessary, we carefully weigh the benefits of making the change against the disruption to existing integrations.

Common reasons include:

* **Adapting to changes from the source** when the source significantly changes or discontinues a dataset, field, or reporting methodology.
* **Correcting implementation errors** where our data or data model did not match the upstream source.
* **Improving our data model** when we determine there is a more accurate or consistent way to represent the data.

## What is a breaking change?

A breaking change is any change that is not backward compatible with existing queries or integrations. Backward-compatible changes, such as adding new columns, are not considered breaking changes.

We treat the following as breaking changes:

* **Removing a column** from a dataset.
* **Renaming a column** from a dataset.
* **Changing a dataset's ID.**
* **Changing dataset metadata** in a way that changes query results, such as its primary key, time index column, publish time column, or subseries index.
* **Deprecating a dataset**, meaning we announce a future date on which it will be removed or stop updating.
* **Retiring a dataset**, meaning it stops receiving new data even though historical data remains queryable.

Some changes are not considered breaking and may ship without advance notice. These include:

* **Adding a new column**
* **Backfilling additional historical data**
* **Correcting data errors** so values match the upstream source.

## How we notify you

We target notifications to customers who use the affected dataset rather than sending every update to every customer. This helps ensure important breaking change notices receive attention instead of getting lost among irrelevant alerts.

* **Who we notify:** Any customer who has queried an affected dataset through our API or Snowflake marketplace in the last 30 days.
* **How we reach you:** By email, sent to the address associated with the API key used to make those queries. Please keep this address monitored.
* **What the notice contains:**
  * The affected dataset and the specific change.
  * The date the change takes effect.
  * The reason for the change.
  * How to update your integration, including a migration path when one is available.
* **Timing:** We aim to give advance notice before a breaking change takes effect when possible.
  * In cases where the upstream source has changed the data we may have to make breaking changes immediately to avoid data loss.
  * When we are able to give advance notice, we will do so at least 10 business days in advance.

## How to respond to a breaking change

1. **Read the notice in full** and identify which datasets, columns, or dataset IDs you depend on.
2. **Follow the migration steps** in the notice to update your queries, column references, or pipeline configuration.
3. **Test against the new behavior** before the effective date. Where possible we give you a way to validate the new schema ahead of time.
4. **Get in touch** if the change affects you in a way the notice does not cover, or if you need more time.

## Questions

If you have questions about this policy or a specific change, contact us at <support@gridstatus.io>.


# Recipes

Complete, copy-paste-ready examples for common energy market analysis tasks using the Grid Status API.

Complete, copy-paste-ready examples for common energy market analysis tasks using the Grid Status API.

## Getting Started

Before using any recipes, make sure you've completed the [Setup](/developers/guides/recipes/setup).

## Available Recipes

* [Pull data for a single node](/developers/guides/recipes/pull-data-for-single-node) - Fetch day-ahead hourly settlement point prices for a specific ERCOT node
* [Get Latest Forecast as of Bid Close](/developers/guides/recipes/ercot-day-ahead-load-forecast-cutoff) - Get the latest ERCOT load forecast available as of day-ahead bid close
* [Backfill and Incrementally Sync a Dataset](/developers/guides/recipes/backfill-and-incremental-sync) - Backfill all available rows, then replicate only new data using a high watermark
* [Trading Hub Price Analysis](/developers/guides/recipes/trading-hub-price-analysis) - Compare prices across trading hubs to identify arbitrage opportunities and congestion patterns
* [Data Freshness Monitoring](/developers/guides/recipes/data-freshness-monitoring) - Monitor data pipeline health and alert on stale data
* [Quota-Aware Batch Processing](/developers/guides/recipes/quota-aware-batch-processing) - Process large date ranges while respecting API quotas

## Related Documentation

* [Best Practices](/developers/guides/best-practices) - Query optimization tips
* [Advanced Query Features](/developers/concepts/query-parameters) - Filtering, resampling, timezone
* [Error Handling](/developers/guides/error-handling) - Handle errors gracefully


# Setup

Setup instructions for all recipe examples

All Python examples in the recipes assume you have initialized the client:

```python
import gridstatusio as gs
client = gs.GridStatusClient(api_key="YOUR_API_KEY")
```

You can [also use the environment variable](https://docs.gridstatus.io/developers/getting-started/python-client) `GRIDSTATUS_API_KEY`.


# Pull data for a single node

Fetch day-ahead hourly settlement point prices for a specific ERCOT node

Fetch day-ahead hourly settlement point prices for a specific ERCOT node.

```python
# Get day-ahead hourly prices for HB_NORTH node
df = client.get_dataset(
    "ercot_spp_day_ahead_hourly",
    start="2026-01-01",
    end="2026-01-08",
    filter_column="location",
    filter_value="HB_NORTH"
)

print(f"Retrieved {len(df)} rows for HB_NORTH")
print(f"\nDate range: {df['interval_start_utc'].min()} to {df['interval_start_utc'].max()}")
print(f"\nPrice statistics:")
print(f"  Mean: ${df['spp'].mean():.2f}/MWh")
print(f"  Max: ${df['spp'].max():.2f}/MWh")
print(f"  Min: ${df['spp'].min():.2f}/MWh")

# Display first few rows
print(f"\nFirst 5 rows:")
print(df.head())
```

You can also omit the `end` parameter to automatically fetch data up to the latest available:

```python
from datetime import datetime

# Get all available data from today (rounded down) through the latest available
df = client.get_dataset(
    "ercot_spp_day_ahead_hourly",
    start=datetime.now().date(),
    filter_column="location",
    filter_value="HB_NORTH"
)

print(f"Retrieved {len(df)} rows for HB_NORTH")
print(f"\nDate range: {df['interval_start_utc'].min()} to {df['interval_start_utc'].max()}")
print(f"\nMost recent price: ${df['spp'].iloc[-1]:.2f}/MWh")
```


# Get Latest Forecast as of Bid Close

Get the latest ERCOT load forecast available as of day-ahead bid close

Pull ERCOT load forecasts by forecast zone as they were available at the 10:00 AM day-ahead bid close, then calculate daily maximums.

## Get hourly forecasts as of bid close

```python
hourly = client.get_dataset(
    "ercot_load_forecast_by_forecast_zone",
    start="2026-05-01",
    end="2026-05-08",
    publish_time="latest_before:-1 day@10:00:00",
    timezone="market",
)

print(hourly.head())
```

For each operating interval, `latest_before:-1 day@10:00:00` selects the latest forecast published at or before 10:00 AM market time on the prior day.

## Calculate daily maximums

```python
daily_max = client.get_dataset(
    "ercot_load_forecast_by_forecast_zone",
    start="2026-04-01",
    end="2026-05-01",
    publish_time="latest_before:-1 day@10:00:00",
    timezone="market",
    resample="1 day",
    resample_function="max",
)

print(daily_max.head())
```


# Backfill and Incrementally Sync a Dataset

Backfill a dataset once, then keep it current with high-watermark incremental syncs

Backfill a Grid Status dataset, then keep your copy current using its latest stored timestamp.

This pattern has two phases:

1. Run an initial backfill with no `start` or `end` parameters to fetch all available rows.
2. Before each later run, derive a high watermark from the latest time-index value in your copy and fetch only newer rows.

## What is a High Watermark?

A high watermark is the latest timestamp your system has successfully written. It is used for determining where the next incremental sync should resume.

{% hint style="info" %}
For datasets with a `publish_time_column`, use the publish time as your high watermark. Forecast datasets, such as [ERCOT Load Forecast by Forecast Zone](https://www.gridstatus.io/datasets/ercot_load_forecast_by_forecast_zone), can publish new versions for the same forecast interval, so watermarking on the time index alone can miss later publications.
{% endhint %}

## Setup

Pick a dataset with a `time_index_column`, then create a local CSV file.

```python
from datetime import UTC, datetime, timedelta
from pathlib import Path

import pandas as pd

DATASET_ID = "ercot_fuel_mix"

data_path = Path(f"{DATASET_ID}.csv")

# Read the time-index column from metadata instead of hard-coding it.
metadata = client.get_dataset_metadata(DATASET_ID)
TIME_INDEX_COLUMN = metadata["time_index_column"]
```

## Phase 1: Initial Backfill

The first run omits `start` and `end`, so it fetches all available rows for the dataset.

```python
print(f"Backfilling all available rows for {DATASET_ID}...")
df = client.get_dataset(DATASET_ID)

df.to_csv(data_path, index=False)

print(f"Backfilled {len(df):,} rows")
```

## Phase 2: Incremental Sync

After the initial backfill, each sync finds the high watermark in the stored data and requests rows after it. Schedule this phase in your own system with a cron job, orchestrated workflow, or manual trigger.

```python
# Grid Status returns rows oldest first, so the last row is the high watermark.
watermark = pd.read_csv(data_path, usecols=[TIME_INDEX_COLUMN]).iloc[-1, 0]

# Grid Status loads complete intervals. Since the API's start filter is
# inclusive, advance slightly to request only records after the last interval
# you stored.
start = (
    datetime.fromisoformat(watermark) + timedelta(microseconds=1)
).isoformat()

print(f"Fetching {DATASET_ID} rows after {watermark}...")
df = client.get_dataset(DATASET_ID, start=start)

if len(df) == 0:
    print("No new rows.")
else:
    # Append only the newly returned rows to the existing local export.
    df.to_csv(data_path, mode="a", header=False, index=False)

    print(f"Synced {len(df):,} rows")
```

For a database or warehouse, use an indexed `MAX(time_index_column)` query instead of reading the last CSV row.

## Use Publish Time for Forecast Datasets

For forecast datasets, use the dataset's `publish_time_column` as the high watermark. Sort by publish time, then time index, before each write so the last stored row always contains the latest publication.

```python
DATASET_ID = "ercot_load_forecast_by_forecast_zone"
data_path = Path(f"{DATASET_ID}.csv")

metadata = client.get_dataset_metadata(DATASET_ID)
WATERMARK_COLUMN = metadata["publish_time_column"]
TIME_INDEX_COLUMN = metadata["time_index_column"]

# Initial backfill: write rows in watermark order.
df = client.get_dataset(DATASET_ID)
df = df.sort_values([WATERMARK_COLUMN, TIME_INDEX_COLUMN])
df.to_csv(data_path, index=False)

# Read the latest publish time already in your destination.
watermark = pd.read_csv(data_path, usecols=[WATERMARK_COLUMN]).iloc[-1, 0]

# Fetch forecasts published after the high watermark.
publish_time_start = (
    datetime.fromisoformat(watermark) + timedelta(microseconds=1)
).isoformat()

df = client.get_dataset(
    DATASET_ID,
    publish_time_start=publish_time_start,
)

if len(df) > 0:
    # Preserve watermark order when appending each incremental batch.
    df = df.sort_values([WATERMARK_COLUMN, TIME_INDEX_COLUMN])
    df.to_csv(data_path, mode="a", header=False, index=False)
```

If you want to be extra conservative and avoid gaps, run each incremental sync with a small overlap window and upsert by the dataset's primary key columns while preserving the same sort order.

## Initial Backfill for Large Datasets

Fetching all available rows in a single request is best suited to smaller datasets. For a large dataset, query the initial backfill one day at a time. Smaller requests limit the amount of work that must be retried after a failure and make it easier to validate that every day was fetched.

This example queries one-day windows beginning January 1, 2025:

```python
day = datetime(2025, 1, 1, tzinfo=UTC)
backfill_end = datetime.now(UTC)

while day < backfill_end:
    next_day = min(day + timedelta(days=1), backfill_end)
    df = client.get_dataset(
        DATASET_ID,
        start=day.isoformat(),
        end=next_day.isoformat(),
        # Uncomment to use market-local time boundaries.
        # timezone="market",
    )
    # Process or store this day's data.
    day = next_day
```

## Periodically Run a Full Reconciliation

If maintaining an exact copy is mission-critical, we recommend complementing incremental syncs with periodic full reconciliations. Re-fetch the complete dataset and reconcile it with your destination. This provides an independent check on the incremental pipeline and increases confidence that missed rows, processing errors, late corrections, and historical revisions are reflected in your copy.

## Avoid Managing Your Own Incremental Sync

If you do not want to operate your own replication pipeline, our [Snowflake Marketplace listing](/developers/snowflake-guides/getting-started) provides SQL access to nearly all Grid Status datasets, generally within 1–2 minutes of API publication. Grid Status keeps the shared tables current, so you do not need to manage backfills or incremental syncs.

For file-based workflows, [Bulk CSV Downloads](/developers/bulk-csv-downloads/getting-started) delivers the complete catalog as compressed CSV files through Amazon S3. Grid Status refreshes the export daily, and a single AWS CLI sync command keeps a local folder current by downloading only missing or changed files, including historical partitions updated with corrections or late-arriving data.


# Trading Hub Price Analysis

Compare prices across trading hubs to identify arbitrage opportunities and congestion patterns

Compare prices across trading hubs to identify arbitrage opportunities and congestion patterns.

```python
import pandas as pd

# Fetch one week of hourly average prices for major ERCOT hubs
df = client.get_dataset(
    "ercot_lmp_by_settlement_point",
    start="2026-01-01",
    end="2026-01-08",
    filter_column="location",
    filter_value="HB_HOUSTON,HB_NORTH,HB_WEST,HB_SOUTH",
    filter_operator="in",
    columns=["interval_start_utc", "location", "lmp"],
    resample="1 hour",
    resample_function="mean"
)

# Pivot to get locations as columns
df_pivot = df.pivot(index='interval_start_utc', columns='location', values='lmp')

# Calculate price spreads
df_pivot['Houston_North'] = df_pivot['HB_HOUSTON'] - df_pivot['HB_NORTH']
df_pivot['Houston_West'] = df_pivot['HB_HOUSTON'] - df_pivot['HB_WEST']

# Summary statistics
print("=== Hub Price Spread Analysis ===")
print(f"\nHouston-North Spread:")
print(f"  Mean: ${df_pivot['Houston_North'].mean():.2f}/MWh")
print(f"  Max: ${df_pivot['Houston_North'].max():.2f}/MWh")
print(f"  Min: ${df_pivot['Houston_North'].min():.2f}/MWh")
print(f"  Std Dev: ${df_pivot['Houston_North'].std():.2f}/MWh")

print(f"\nHouston-West Spread:")
print(f"  Mean: ${df_pivot['Houston_West'].mean():.2f}/MWh")
print(f"  Max: ${df_pivot['Houston_West'].max():.2f}/MWh")

# Find hours with largest spreads (potential congestion)
print(f"\n=== Top 5 Hours with Largest Houston-North Spread ===")
top_spreads = df_pivot.nlargest(5, 'Houston_North')[['HB_HOUSTON', 'HB_NORTH', 'Houston_North']]
print(top_spreads)
```


# Data Freshness Monitoring

Monitor data pipeline health and alert on stale data

Monitor data pipeline health and alert on stale data.

```python
from datetime import datetime, timezone, timedelta

# Datasets to monitor with expected update frequencies
MONITORED_DATASETS = {
    "ercot_fuel_mix": timedelta(minutes=10),
    "ercot_load": timedelta(minutes=10),
    "ercot_lmp_by_settlement_point": timedelta(minutes=10),
    "caiso_lmp_real_time_5_min": timedelta(minutes=10),
    "pjm_load": timedelta(minutes=15),
}

def check_all_datasets():
    """Check freshness of all monitored datasets."""
    now = datetime.now(timezone.utc)
    issues = []

    for dataset_id, max_age in MONITORED_DATASETS.items():
        metadata = client.get(
                f"{client.host}/datasets/{dataset_id}",
                return_raw_response_json=True
        )

        latest = datetime.fromisoformat(
            metadata['latest_available_time_utc'].replace('Z', '+00:00')
        )
        age = now - latest

        status = "OK" if age <= max_age * 2 else "STALE"
        age_str = f"{age.total_seconds() / 60:.0f} min"

        if status == "STALE":
            issues.append({
                'dataset': dataset_id,
                'age': age_str,
                'expected': f"{max_age.total_seconds() / 60:.0f} min"
            })

        print(f"[{status}] {dataset_id}: {age_str} old")

    return issues

print("=== Data Freshness Check ===")
print(f"Timestamp: {datetime.now(timezone.utc).isoformat()}\n")

issues = check_all_datasets()

if issues:
    print(f"\n*** ALERT: {len(issues)} datasets are stale ***")
    for issue in issues:
        print(f"  {issue['dataset']}: {issue['age']} old (expected: {issue['expected']})")
else:
    print("\nAll datasets are fresh.")
```


# Quota-Aware Batch Processing

Process large date ranges while respecting API quotas

Process large date ranges while respecting API quotas.

```python
import pandas as pd
from datetime import datetime, timedelta

def safe_batch_query(
    dataset: str,
    start: datetime,
    end: datetime,
    batch_days: int = 7,
    min_quota_buffer: int = 100000,
    **kwargs
) -> pd.DataFrame:
    """Fetch data in batches, checking quota before each batch."""
    all_data = []
    current = start

    while current < end:
        # Check remaining quota
        usage = client.get_api_usage()
        rows_remaining = (
            usage['limits']['api_rows_returned_limit'] -
            usage['current_period_usage']['total_api_rows_returned']
        )

        if rows_remaining < min_quota_buffer:
            print(f"Stopping: Only {rows_remaining:,} rows remaining in quota")
            break

        batch_end = min(current + timedelta(days=batch_days), end)
        print(f"Fetching {current.date()} to {batch_end.date()} (quota: {rows_remaining:,} remaining)...")

        df = client.get_dataset(
            dataset,
            start=current.isoformat(),
            end=batch_end.isoformat(),
            **kwargs
        )

        if len(df) > 0:
            all_data.append(df)
            print(f"  Retrieved {len(df):,} rows")

        current = batch_end

    if all_data:
        return pd.concat(all_data, ignore_index=True)
    return pd.DataFrame()

# Example: Fetch two weeks of data in weekly batches
df = safe_batch_query(
    "ercot_fuel_mix",
    start=datetime(2026, 1, 1),
    end=datetime(2026, 1, 15),
    batch_days=7
)

print(f"\nTotal rows retrieved: {len(df):,}")
```


# API Info

## GET /

> API Info

```json
{"openapi":"3.1.0","info":{"title":"Grid Status API","version":"1.3.0"},"servers":[{"url":"https://api.gridstatus.io/v1"}],"paths":{"/":{"get":{"tags":["API Info"],"summary":"API Info","operationId":"api_info_v1__get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/APIInfoResponse"}}}}}}}},"components":{"schemas":{"APIInfoResponse":{"properties":{"name":{"type":"string","title":"Name"},"version":{"type":"string","title":"Version"}},"type":"object","required":["name","version"],"title":"APIInfoResponse"}}}}
```


# Block Pricing Data

## Get Block Pricing

> Returns block-averaged prices for an ISO over the requested date range.\
> \
> The response is a list of columns. Daily columns (keyed by ISO date) cover the requested range, and additional summary columns are appended: \`MTD\` (month-to-date) and a \`Month-Year\` label for each full month spanned. Each column's \`value\` is the volume-weighted average price for the block over that window.\
> \
> Each datum includes \`pct\_change\`, the percent change of \`value\` relative to the previous period for the same market and block (prior market day for daily columns; prior calendar month for summary columns). It is null when the previous period has no value or when the prior value is zero.\
> \
> The \`complete\` flag indicates whether every interval in the window has reported data; it is \`false\` for in-progress windows such as the current day or month-to-date.

```json
{"openapi":"3.1.0","info":{"title":"Grid Status API","version":"1.3.0"},"servers":[{"url":"https://api.gridstatus.io/v1"}],"paths":{"/block-pricing/{iso}":{"get":{"tags":["Block Pricing Data"],"summary":"Get Block Pricing","description":"Returns block-averaged prices for an ISO over the requested date range.\n\nThe response is a list of columns. Daily columns (keyed by ISO date) cover the requested range, and additional summary columns are appended: `MTD` (month-to-date) and a `Month-Year` label for each full month spanned. Each column's `value` is the volume-weighted average price for the block over that window.\n\nEach datum includes `pct_change`, the percent change of `value` relative to the previous period for the same market and block (prior market day for daily columns; prior calendar month for summary columns). It is null when the previous period has no value or when the prior value is zero.\n\nThe `complete` flag indicates whether every interval in the window has reported data; it is `false` for in-progress windows such as the current day or month-to-date.","operationId":"get_block_pricing_v1_block_pricing__iso__get","parameters":[{"name":"iso","in":"path","required":true,"schema":{"$ref":"#/components/schemas/ISOEnum","description":"ISO identifier used to resolve the backing block pricing dataset."},"description":"ISO identifier used to resolve the backing block pricing dataset."},{"name":"params","in":"query","required":true,"schema":{"$ref":"#/components/schemas/BlockPricingQueryParams"}},{"name":"api_key","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"API key for authentication (query)","title":"Api Key"},"description":"API key for authentication (query)"},{"name":"x-api-key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"API key for authentication (header)","title":"X-Api-Key"},"description":"API key for authentication (header)"}],"responses":{"200":{"description":"Successful response","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/BlockPricingDateGroup"},"title":"Response Get Block Pricing V1 Block Pricing  Iso  Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}}},"components":{"schemas":{"ISOEnum":{"type":"string","enum":["CAISO","ERCOT","IESO","ISONE","MISO","NYISO","PJM","SPP"],"title":"ISOEnum"},"BlockPricingQueryParams":{"properties":{"start_date":{"type":"string","format":"date","title":"Start Date","description":"Start of date range (inclusive), interpreted in the ISO market timezone."},"end_date":{"type":"string","format":"date","title":"End Date","description":"End of date range (exclusive), interpreted in the ISO market timezone."},"location":{"type":"string","title":"Location","description":"Location filter."},"market":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Market","description":"Optional market filter. Allowed values: \"da\" or \"rt\"."},"blocks":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Blocks","description":"Optional comma-separated list of block values. Allowed values: 7x24, 7x8, 2x16h, on-peak, off-peak."}},"type":"object","required":["start_date","end_date","location"],"title":"BlockPricingQueryParams"},"BlockPricingDateGroup":{"properties":{"date":{"type":"string","title":"Date","description":"Column identifier: an ISO date (YYYY-MM-DD) for a daily column, \"MTD\" for month-to-date, or a \"Month-Year\" label for a full-month summary."},"is_nerc_holiday":{"type":"boolean","title":"Is Nerc Holiday","description":"Whether the daily column is a NERC holiday. False for summary columns.","default":false},"data":{"items":{"$ref":"#/components/schemas/BlockPricingDatum"},"type":"array","title":"Data","description":"Block values for this column, one entry per market/block."}},"type":"object","required":["date","data"],"title":"BlockPricingDateGroup","description":"All block values for a single response column."},"BlockPricingDatum":{"properties":{"market":{"type":"string","title":"Market","description":"Market the value is for (\"da\" or \"rt\")."},"block":{"type":"string","title":"Block","description":"Block the value is for (e.g. 7x24, on-peak, off-peak)."},"value":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Value","description":"Volume-weighted average price for the block over the column's window, or null when no data is available."},"pct_change":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Pct Change","description":"Percent change of `value` relative to the previous period for the same market and block (e.g. the prior market day for daily columns, or the prior calendar month for summary columns). Null when the previous period has no value or when the prior value is zero."},"complete":{"type":"boolean","title":"Complete","description":"Whether every interval in the column's window has reported data. False for in-progress windows (e.g. the current day or month-to-date)."}},"type":"object","required":["market","block","value","pct_change","complete"],"title":"BlockPricingDatum","description":"A single block's value for one column (a day or a summary period)."},"HTTPValidationError":{"properties":{"detail":{"items":{"$ref":"#/components/schemas/ValidationError"},"type":"array","title":"Detail"}},"type":"object","title":"HTTPValidationError"},"ValidationError":{"properties":{"loc":{"items":{"anyOf":[{"type":"string"},{"type":"integer"}]},"type":"array","title":"Location"},"msg":{"type":"string","title":"Message"},"type":{"type":"string","title":"Error Type"}},"type":"object","required":["loc","msg","type"],"title":"ValidationError"}}}}
```


# Dataset Metadata

## List Datasets

> List all published datasets a user has access to\
> \
> See list of available datasets here: <https://www.gridstatus.io/datasets>

```json
{"openapi":"3.1.0","info":{"title":"Grid Status API","version":"1.3.0"},"servers":[{"url":"https://api.gridstatus.io/v1"}],"paths":{"/datasets":{"get":{"tags":["Dataset Metadata"],"summary":"List Datasets","description":"List all published datasets a user has access to\n\nSee list of available datasets here: https://www.gridstatus.io/datasets","operationId":"list_datasets_v1_datasets_get","parameters":[{"name":"api_key","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"API key for authentication (query)","title":"Api Key"},"description":"API key for authentication (query)"},{"name":"return_format","in":"query","required":false,"schema":{"$ref":"#/components/schemas/ReturnFormat","description":"The return format of the response","default":"json"},"description":"The return format of the response"},{"name":"download","in":"query","required":false,"schema":{"type":"boolean","description":"Whether to download the file or not","default":false,"title":"Download"},"description":"Whether to download the file or not"},{"name":"json_schema","in":"query","required":false,"schema":{"$ref":"#/components/schemas/JSONSchema","description":"The json schema of the response","default":"array-of-objects"},"description":"The json schema of the response"},{"name":"x-api-key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"API key for authentication (header)","title":"X-Api-Key"},"description":"API key for authentication (header)"}],"responses":{"200":{"description":"Successful response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ListDatasetsResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}}},"components":{"schemas":{"ReturnFormat":{"type":"string","enum":["json","csv"],"title":"ReturnFormat"},"JSONSchema":{"type":"string","enum":["array-of-objects","array-of-arrays"],"title":"JSONSchema"},"ListDatasetsResponse":{"properties":{"status_code":{"type":"integer","title":"Status Code"},"data":{"items":{"$ref":"#/components/schemas/DatasetResponse"},"type":"array","title":"Data"},"meta":{"$ref":"#/components/schemas/MetadataResponse"},"dataset_metadata":{"$ref":"#/components/schemas/ListDatasetsDatasetMetadataResponse"}},"type":"object","required":["status_code","data","meta","dataset_metadata"],"title":"ListDatasetsResponse"},"DatasetResponse":{"properties":{"id":{"type":"string","title":"Id"},"name":{"type":"string","title":"Name"},"description":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Description"},"earliest_available_time_utc":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Earliest Available Time Utc"},"latest_available_time_utc":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Latest Available Time Utc"},"source":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Source"},"last_checked_time_utc":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Last Checked Time Utc"},"primary_key_columns":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"null"}],"title":"Primary Key Columns"},"publish_time_column":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Publish Time Column"},"time_index_column":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Time Index Column"},"subseries_index_column":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Subseries Index Column"},"all_columns":{"anyOf":[{"items":{"$ref":"#/components/schemas/ColumnResponse"},"type":"array"},{"type":"null"}],"title":"All Columns"},"number_of_rows_approximate":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Number Of Rows Approximate"},"table_type":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Table Type"},"is_in_snowflake":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Is In Snowflake"},"data_frequency":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Data Frequency"},"source_url":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Source Url"},"publication_frequency":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Publication Frequency"},"is_published":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Is Published"},"created_at_utc":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Created At Utc"},"status":{"anyOf":[{"$ref":"#/components/schemas/DatasetStatusEnum"},{"type":"null"}]},"popularity_rank":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Popularity Rank"}},"type":"object","required":["id","name","description","earliest_available_time_utc","latest_available_time_utc","source","last_checked_time_utc","primary_key_columns","publish_time_column","time_index_column","subseries_index_column","all_columns","number_of_rows_approximate","table_type","is_in_snowflake","data_frequency","source_url","publication_frequency","is_published","created_at_utc","status"],"title":"DatasetResponse"},"ColumnResponse":{"properties":{"name":{"type":"string","title":"Name"},"type":{"type":"string","title":"Type"},"is_numeric":{"type":"boolean","title":"Is Numeric"},"is_date":{"type":"boolean","title":"Is Date","default":false},"is_datetime":{"type":"boolean","title":"Is Datetime"}},"type":"object","required":["name","type","is_numeric","is_datetime"],"title":"ColumnResponse"},"DatasetStatusEnum":{"type":"string","enum":["retired","active","deprecated"],"title":"DatasetStatusEnum"},"MetadataResponse":{"properties":{"page":{"type":"integer","title":"Page"},"limit":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Limit"},"page_size":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Page Size"},"hasNextPage":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Hasnextpage"},"cursor":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Cursor"}},"type":"object","required":["page","limit","page_size","hasNextPage","cursor"],"title":"MetadataResponse"},"ListDatasetsDatasetMetadataResponse":{"properties":{"resample_conversion":{"additionalProperties":{"type":"integer"},"type":"object","title":"Resample Conversion","default":{"1_MINUTE":60,"5_MINUTES":300,"10_MINUTES":600,"15_MINUTES":900,"1_HOUR":3600,"1_DAY":86400,"1_DAY_MARKET":86400,"1_WEEK":604800,"1_MONTH":2592000,"1_YEAR":31536000,"IRREGULAR":-1}}},"type":"object","title":"ListDatasetsDatasetMetadataResponse"},"HTTPValidationError":{"properties":{"detail":{"items":{"$ref":"#/components/schemas/ValidationError"},"type":"array","title":"Detail"}},"type":"object","title":"HTTPValidationError"},"ValidationError":{"properties":{"loc":{"items":{"anyOf":[{"type":"string"},{"type":"integer"}]},"type":"array","title":"Location"},"msg":{"type":"string","title":"Message"},"type":{"type":"string","title":"Error Type"}},"type":"object","required":["loc","msg","type"],"title":"ValidationError"}}}}
```

## Get Dataset Metadata

> Get a dataset and its metadata

```json
{"openapi":"3.1.0","info":{"title":"Grid Status API","version":"1.3.0"},"servers":[{"url":"https://api.gridstatus.io/v1"}],"paths":{"/datasets/{dataset_id}":{"get":{"tags":["Dataset Metadata"],"summary":"Get Dataset Metadata","description":"Get a dataset and its metadata","operationId":"get_dataset_metadata_v1_datasets__dataset_id__get","parameters":[{"name":"dataset_id","in":"path","required":true,"schema":{"type":"string","title":"Dataset Id"}},{"name":"api_key","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"API key for authentication (query)","title":"Api Key"},"description":"API key for authentication (query)"},{"name":"return_format","in":"query","required":false,"schema":{"$ref":"#/components/schemas/ReturnFormat","description":"The return format of the response","default":"json"},"description":"The return format of the response"},{"name":"download","in":"query","required":false,"schema":{"type":"boolean","description":"Whether to download the file or not","default":false,"title":"Download"},"description":"Whether to download the file or not"},{"name":"json_schema","in":"query","required":false,"schema":{"$ref":"#/components/schemas/JSONSchema","description":"The json schema of the response","default":"array-of-objects"},"description":"The json schema of the response"},{"name":"x-api-key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"API key for authentication (header)","title":"X-Api-Key"},"description":"API key for authentication (header)"}],"responses":{"200":{"description":"Successful response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DatasetResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}}},"components":{"schemas":{"ReturnFormat":{"type":"string","enum":["json","csv"],"title":"ReturnFormat"},"JSONSchema":{"type":"string","enum":["array-of-objects","array-of-arrays"],"title":"JSONSchema"},"DatasetResponse":{"properties":{"id":{"type":"string","title":"Id"},"name":{"type":"string","title":"Name"},"description":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Description"},"earliest_available_time_utc":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Earliest Available Time Utc"},"latest_available_time_utc":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Latest Available Time Utc"},"source":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Source"},"last_checked_time_utc":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Last Checked Time Utc"},"primary_key_columns":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"null"}],"title":"Primary Key Columns"},"publish_time_column":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Publish Time Column"},"time_index_column":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Time Index Column"},"subseries_index_column":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Subseries Index Column"},"all_columns":{"anyOf":[{"items":{"$ref":"#/components/schemas/ColumnResponse"},"type":"array"},{"type":"null"}],"title":"All Columns"},"number_of_rows_approximate":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Number Of Rows Approximate"},"table_type":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Table Type"},"is_in_snowflake":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Is In Snowflake"},"data_frequency":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Data Frequency"},"source_url":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Source Url"},"publication_frequency":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Publication Frequency"},"is_published":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Is Published"},"created_at_utc":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Created At Utc"},"status":{"anyOf":[{"$ref":"#/components/schemas/DatasetStatusEnum"},{"type":"null"}]},"popularity_rank":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Popularity Rank"}},"type":"object","required":["id","name","description","earliest_available_time_utc","latest_available_time_utc","source","last_checked_time_utc","primary_key_columns","publish_time_column","time_index_column","subseries_index_column","all_columns","number_of_rows_approximate","table_type","is_in_snowflake","data_frequency","source_url","publication_frequency","is_published","created_at_utc","status"],"title":"DatasetResponse"},"ColumnResponse":{"properties":{"name":{"type":"string","title":"Name"},"type":{"type":"string","title":"Type"},"is_numeric":{"type":"boolean","title":"Is Numeric"},"is_date":{"type":"boolean","title":"Is Date","default":false},"is_datetime":{"type":"boolean","title":"Is Datetime"}},"type":"object","required":["name","type","is_numeric","is_datetime"],"title":"ColumnResponse"},"DatasetStatusEnum":{"type":"string","enum":["retired","active","deprecated"],"title":"DatasetStatusEnum"},"HTTPValidationError":{"properties":{"detail":{"items":{"$ref":"#/components/schemas/ValidationError"},"type":"array","title":"Detail"}},"type":"object","title":"HTTPValidationError"},"ValidationError":{"properties":{"loc":{"items":{"anyOf":[{"type":"string"},{"type":"integer"}]},"type":"array","title":"Location"},"msg":{"type":"string","title":"Message"},"type":{"type":"string","title":"Error Type"}},"type":"object","required":["loc","msg","type"],"title":"ValidationError"}}}}
```


# Dataset Audit

## Get Dataset Audit

> Returns audit data by market date for a given dataset\
> \
> \* market\_date: The market date for which the audit data is being returned\
> \
> \* number\_of\_datapoints: The total number of rows\
> \
> \* number\_of\_unique\_time\_index\_values: The total number of unique time index\
> &#x20; values\
> \
> \* number\_of\_unique\_subseries\_index\_values: The total number of unique\
> &#x20; subseries index values\
> \
> \* number\_of\_unique\_publish\_times\_on\_publish\_date: The total number of\
> &#x20; unique publish time values where the publish time occurred on the given\
> &#x20; market date

```json
{"openapi":"3.1.0","info":{"title":"Grid Status API","version":"1.3.0"},"servers":[{"url":"https://api.gridstatus.io/v1"}],"paths":{"/datasets/{dataset_id}/audit":{"get":{"tags":["Dataset Audit"],"summary":"Get Dataset Audit","description":"Returns audit data by market date for a given dataset\n\n* market_date: The market date for which the audit data is being returned\n\n* number_of_datapoints: The total number of rows\n\n* number_of_unique_time_index_values: The total number of unique time index\n  values\n\n* number_of_unique_subseries_index_values: The total number of unique\n  subseries index values\n\n* number_of_unique_publish_times_on_publish_date: The total number of\n  unique publish time values where the publish time occurred on the given\n  market date","operationId":"get_dataset_audit_v1_datasets__dataset_id__audit_get","parameters":[{"name":"dataset_id","in":"path","required":true,"schema":{"type":"string","title":"Dataset Id"}},{"name":"api_key","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"API key for authentication (query)","title":"Api Key"},"description":"API key for authentication (query)"},{"name":"return_format","in":"query","required":false,"schema":{"$ref":"#/components/schemas/ReturnFormat","description":"The return format of the response","default":"json"},"description":"The return format of the response"},{"name":"download","in":"query","required":false,"schema":{"type":"boolean","description":"Whether to download the file or not","default":false,"title":"Download"},"description":"Whether to download the file or not"},{"name":"json_schema","in":"query","required":false,"schema":{"$ref":"#/components/schemas/JSONSchema","description":"The json schema of the response","default":"array-of-objects"},"description":"The json schema of the response"},{"name":"x-api-key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"API key for authentication (header)","title":"X-Api-Key"},"description":"API key for authentication (header)"}],"responses":{"200":{"description":"Successful response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DatasetAuditResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}}},"components":{"schemas":{"ReturnFormat":{"type":"string","enum":["json","csv"],"title":"ReturnFormat"},"JSONSchema":{"type":"string","enum":["array-of-objects","array-of-arrays"],"title":"JSONSchema"},"DatasetAuditResponse":{"properties":{"status_code":{"type":"integer","title":"Status Code"},"data":{"items":{"$ref":"#/components/schemas/DatasetAudit"},"type":"array","title":"Data"}},"type":"object","required":["status_code","data"],"title":"DatasetAuditResponse"},"DatasetAudit":{"properties":{"market_date":{"anyOf":[{"type":"string","format":"date"},{"type":"null"}],"title":"Market Date"},"number_of_datapoints":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Number Of Datapoints"},"number_of_unique_time_index_values":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Number Of Unique Time Index Values"},"number_of_unique_subseries_index_values":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Number Of Unique Subseries Index Values"},"number_of_unique_publish_times_on_publish_date":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Number Of Unique Publish Times On Publish Date"}},"type":"object","required":["market_date","number_of_datapoints","number_of_unique_time_index_values","number_of_unique_subseries_index_values","number_of_unique_publish_times_on_publish_date"],"title":"DatasetAudit"},"HTTPValidationError":{"properties":{"detail":{"items":{"$ref":"#/components/schemas/ValidationError"},"type":"array","title":"Detail"}},"type":"object","title":"HTTPValidationError"},"ValidationError":{"properties":{"loc":{"items":{"anyOf":[{"type":"string"},{"type":"integer"}]},"type":"array","title":"Location"},"msg":{"type":"string","title":"Message"},"type":{"type":"string","title":"Error Type"}},"type":"object","required":["loc","msg","type"],"title":"ValidationError"}}}}
```


# Query Data

## Query Dataset

> Query a dataset and return matching rows as JSON or CSV.\
> \
> Pass the \`\`X-Stream: true\`\` request header to stream JSON rows directly from a\
> Postgres server-side cursor instead of buffering the entire result set in\
> memory first (JSON only; ignored for CSV and external datasets). In streaming\
> mode the result-dependent \`\`X-Has-Next-Page\`\` and \`\`X-rows-in-response\`\`\
> headers are omitted -- read pagination from the JSON \`\`meta.hasNextPage\`\` and\
> \`\`meta.cursor\`\` fields, which are populated identically on both paths.

```json
{"openapi":"3.1.0","info":{"title":"Grid Status API","version":"1.3.0"},"servers":[{"url":"https://api.gridstatus.io/v1"}],"paths":{"/datasets/{dataset_id}/query":{"get":{"tags":["Query Data"],"summary":"Query Dataset","description":"Query a dataset and return matching rows as JSON or CSV.\n\nPass the ``X-Stream: true`` request header to stream JSON rows directly from a\nPostgres server-side cursor instead of buffering the entire result set in\nmemory first (JSON only; ignored for CSV and external datasets). In streaming\nmode the result-dependent ``X-Has-Next-Page`` and ``X-rows-in-response``\nheaders are omitted -- read pagination from the JSON ``meta.hasNextPage`` and\n``meta.cursor`` fields, which are populated identically on both paths.","operationId":"query_dataset_v1_datasets__dataset_id__query_get","parameters":[{"name":"dataset_id","in":"path","required":true,"schema":{"type":"string","title":"Dataset ID","description":"ID of the dataset to query"},"description":"ID of the dataset to query"},{"name":"api_key","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"API key for authentication (query)","title":"Api Key"},"description":"API key for authentication (query)"},{"name":"order","in":"query","required":false,"schema":{"anyOf":[{"$ref":"#/components/schemas/OrderBy"},{"type":"null"}],"description":"The order to order results by","default":"asc","title":"Order"},"description":"The order to order results by"},{"name":"filter_column","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"The column to filter results by","title":"Filter Column"},"description":"The column to filter results by"},{"name":"filter_value","in":"query","required":false,"schema":{"anyOf":[{"type":"integer"},{"type":"number"},{"type":"string"},{"type":"null"}],"description":"The value to filter results by","title":"Filter Value"},"description":"The value to filter results by"},{"name":"filter_operator","in":"query","required":false,"schema":{"anyOf":[{"$ref":"#/components/schemas/FilterOperator"},{"type":"null"}],"default":"=","title":"Filter Operator"}},{"name":"limit","in":"query","required":false,"schema":{"anyOf":[{"type":"integer"},{"type":"null"}],"description":"The maximum number of rows to return across all pages","title":"Limit"},"description":"The maximum number of rows to return across all pages"},{"name":"page","in":"query","required":false,"schema":{"type":"integer","description":"The page number of results to return","default":1,"title":"Page"},"description":"The page number of results to return"},{"name":"page_size","in":"query","required":false,"schema":{"anyOf":[{"type":"integer"},{"type":"null"}],"description":"The maximum number of rows to return in a single page","title":"Page Size"},"description":"The maximum number of rows to return in a single page"},{"name":"columns","in":"query","required":false,"schema":{"anyOf":[{"type":"array","items":{"type":"string"}},{"type":"string"},{"type":"null"}],"description":"Comma separated list of columns to return. Defaults to all columns.","title":"Columns"},"description":"Comma separated list of columns to return. Defaults to all columns."},{"name":"cursor","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Cursor"}},{"name":"timezone","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"The timezone to use when interpreting timezone naive timestamps, resampling to frequencies one day or more, and returning results. A value of `market`can be provided to return results in the timezone of the source ISO for the dataset. If `market` is specified and the dataset does not have a source ISO, the timezone will default to UTC for the query. When provided, columns in the `timezone` will be suffixed with `_local`.","default":"UTC","title":"Timezone"},"description":"The timezone to use when interpreting timezone naive timestamps, resampling to frequencies one day or more, and returning results. A value of `market`can be provided to return results in the timezone of the source ISO for the dataset. If `market` is specified and the dataset does not have a source ISO, the timezone will default to UTC for the query. When provided, columns in the `timezone` will be suffixed with `_local`."},{"name":"time","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"string","format":"date-time"},{"type":"null"}],"description":"The time to filter results. Cannot be used with start_time or end_time.\n\nPossible values:\n\n- 'latest': Fetches the most recently reported data point.\n\n- A specific timestamp string (ISO 8601 format): Returns records that were published at the provided timestamp.\n\n","title":"Time"},"description":"The time to filter results. Cannot be used with start_time or end_time.\n\nPossible values:\n\n- 'latest': Fetches the most recently reported data point.\n\n- A specific timestamp string (ISO 8601 format): Returns records that were published at the provided timestamp.\n\n"},{"name":"time_comparison","in":"query","required":false,"schema":{"anyOf":[{"enum":["=",">",">=","<","<="],"type":"string"},{"type":"null"}],"description":"The comparison operator to use when filtering by time.\n\nPossible values:\n\n- '=': Fetches the data at the exact time.\n\n- '>': Fetches the earliest data after the provided time.\n\n- '>=': Fetches the earliest data on or after the provided time.\n\n- '<': Fetches the latest data before the provided time.\n\n- '<=': Fetches the latest data on or before the provided time.\n\n","default":"=","title":"Time Comparison"},"description":"The comparison operator to use when filtering by time.\n\nPossible values:\n\n- '=': Fetches the data at the exact time.\n\n- '>': Fetches the earliest data after the provided time.\n\n- '>=': Fetches the earliest data on or after the provided time.\n\n- '<': Fetches the latest data before the provided time.\n\n- '<=': Fetches the latest data on or before the provided time.\n\n"},{"name":"start_time","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"string","format":"date-time"},{"type":"null"}],"description":"The start time to filter results using the dataset's time_index_column. Data on or after this time will be returned. Only applies to datasets with a time_index_column","title":"Start Time"},"description":"The start time to filter results using the dataset's time_index_column. Data on or after this time will be returned. Only applies to datasets with a time_index_column"},{"name":"end_time","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"string","format":"date-time"},{"type":"null"}],"description":"The end time to filter results using the dataset's time_index_column. Data before this time will be returned. Only applies to datasets with a time_index_column","title":"End Time"},"description":"The end time to filter results using the dataset's time_index_column. Data before this time will be returned. Only applies to datasets with a time_index_column"},{"name":"publish_time","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"string","format":"date-time"},{"type":"null"}],"description":"Controls the filtering based on the dataset's publish time.\n\nCannot be combined with publish_time_start or publish_time_end.Note: a dataset must have a time index column to use 'latest' or 'latest_before:' options.\n\nPossible values:\n\n- 'latest_report': Returns records only from the most recently published report.\n\n- 'latest': For any given timestamp, fetches the most recently reported data point associated with it.\n\n- A specific timestamp string (ISO 8601 format): Returns records that were published at the provided timestamp.\n\n- 'latest_before:<offset>': Return the most recent forecast for each operating time where publish_time <= operating_time + offset (e.g., 'latest_before:-6 hours').\n\n - 'latest_before': shorthand for 'latest_before:-0 hours'. Used to get the most recent forecast prior to each operating time. This is useful because some forecasts are published after the operating time they are forecasting for.\n\n- 'latest_before:<offset>@<HH:MM:SS>': Return the latest forecast published before the specified time on the offset day (e.g., 'latest_before:-1 day@10:00:00').\n\n - 'window':<offset>: Returns all forecasts for each operating time published between the specified offset from the operating time and the operating time. In other words, where operating_time + offset <= publish_time <= operating_time. (e.g., 'window:-6 hours').\n\n - 'window:<offset>@<HH:MM:SS>': Returns all forecasts for each operating time published between the specified time on the offset day from the operating time and the operating time (e.g., 'window:-1 day@10:00:00').\n\n- None: No filtering based on publish time.\n\n","title":"Publish Time"},"description":"Controls the filtering based on the dataset's publish time.\n\nCannot be combined with publish_time_start or publish_time_end.Note: a dataset must have a time index column to use 'latest' or 'latest_before:' options.\n\nPossible values:\n\n- 'latest_report': Returns records only from the most recently published report.\n\n- 'latest': For any given timestamp, fetches the most recently reported data point associated with it.\n\n- A specific timestamp string (ISO 8601 format): Returns records that were published at the provided timestamp.\n\n- 'latest_before:<offset>': Return the most recent forecast for each operating time where publish_time <= operating_time + offset (e.g., 'latest_before:-6 hours').\n\n - 'latest_before': shorthand for 'latest_before:-0 hours'. Used to get the most recent forecast prior to each operating time. This is useful because some forecasts are published after the operating time they are forecasting for.\n\n- 'latest_before:<offset>@<HH:MM:SS>': Return the latest forecast published before the specified time on the offset day (e.g., 'latest_before:-1 day@10:00:00').\n\n - 'window':<offset>: Returns all forecasts for each operating time published between the specified offset from the operating time and the operating time. In other words, where operating_time + offset <= publish_time <= operating_time. (e.g., 'window:-6 hours').\n\n - 'window:<offset>@<HH:MM:SS>': Returns all forecasts for each operating time published between the specified time on the offset day from the operating time and the operating time (e.g., 'window:-1 day@10:00:00').\n\n- None: No filtering based on publish time.\n\n"},{"name":"publish_time_start","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"string","format":"date-time"},{"type":"null"}],"description":"The start time to filter results using the dataset's publish_time_column. Data on or after this time will be returned up to the publish_time_end if provided. Only applies to datasets with a publish_time_column. Cannot be used with publish_time.","title":"Publish Time Start"},"description":"The start time to filter results using the dataset's publish_time_column. Data on or after this time will be returned up to the publish_time_end if provided. Only applies to datasets with a publish_time_column. Cannot be used with publish_time."},{"name":"publish_time_end","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"string","format":"date-time"},{"type":"null"}],"description":"The end time to filter results using the dataset's publish_index_column. Data before this time will be returned down the publish_time_start if provided. Only applies to datasets with a publish_time_column. Cannot be used with publish_time.","title":"Publish Time End"},"description":"The end time to filter results using the dataset's publish_index_column. Data before this time will be returned down the publish_time_start if provided. Only applies to datasets with a publish_time_column. Cannot be used with publish_time."},{"name":"resample_frequency","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"The frequency to resample the data to. Must be one of:\n\n- \"1 minute\"\n- \"5 minutes\"\n- \"10 minutes\"\n- \"15 minutes\"\n- \"1 hour\"\n- \"1 day\"\n- \"1 week\"\n- \"1 month\"\n- \"1 year\"\n\nWhen resampling_frequency is specified, start_time and end_time values must also be provided. The only exception to this is when querying datasets that have a publish time and the publish time is specified as a specific timestamp or 'latest_report'.\n\nAdditionally, the number of days of data that can be queried is limited based on the resample frequency. The maximum number of days of data that can be queried for each resample frequency is listed below. There is no limit on days for resample frequencies not listed below.\n\n- 1 minute: 31 days\n- 5 minutes: 100 days\n- 10 minutes: 120 days\n- 15 minutes: 180 days\n- 1 hour: 365 days\n- 1 day: 1825 days","title":"Resample Frequency"},"description":"The frequency to resample the data to. Must be one of:\n\n- \"1 minute\"\n- \"5 minutes\"\n- \"10 minutes\"\n- \"15 minutes\"\n- \"1 hour\"\n- \"1 day\"\n- \"1 week\"\n- \"1 month\"\n- \"1 year\"\n\nWhen resampling_frequency is specified, start_time and end_time values must also be provided. The only exception to this is when querying datasets that have a publish time and the publish time is specified as a specific timestamp or 'latest_report'.\n\nAdditionally, the number of days of data that can be queried is limited based on the resample frequency. The maximum number of days of data that can be queried for each resample frequency is listed below. There is no limit on days for resample frequencies not listed below.\n\n- 1 minute: 31 days\n- 5 minutes: 100 days\n- 10 minutes: 120 days\n- 15 minutes: 180 days\n- 1 hour: 365 days\n- 1 day: 1825 days"},{"name":"resample_by","in":"query","required":false,"schema":{"anyOf":[{"type":"array","items":{"type":"string"}},{"type":"string"},{"type":"null"}],"description":"A comma separated list of columns to group by before resampling. \n\n- When resampling, the data is always grouped by the time index column of the dataset.\n\n- If a value is provided for resample_by, the data will be grouped by the provided columns in addition to the time index column.\n\n- If the dataset has a subseries index and no value is provided for resample_by, the data will also be grouped by the subseries index column.\n\n- If the dataset has a publish time column and the publish_time parameter is not 'latest', the data will also be grouped by the publish time column.","title":"Resample By"},"description":"A comma separated list of columns to group by before resampling. \n\n- When resampling, the data is always grouped by the time index column of the dataset.\n\n- If a value is provided for resample_by, the data will be grouped by the provided columns in addition to the time index column.\n\n- If the dataset has a subseries index and no value is provided for resample_by, the data will also be grouped by the subseries index column.\n\n- If the dataset has a publish time column and the publish_time parameter is not 'latest', the data will also be grouped by the publish time column."},{"name":"resample_function","in":"query","required":false,"schema":{"anyOf":[{"$ref":"#/components/schemas/ResampleFunction"},{"type":"null"}],"description":"The function to use when resampling. Defaults to \"mean\". Possible values are \"mean\", \"sum\", \"min\", \"max\", \"count\", \"stddev\", \"variance\". If resample is None, this is ignored.","default":"mean","title":"Resample Function"},"description":"The function to use when resampling. Defaults to \"mean\". Possible values are \"mean\", \"sum\", \"min\", \"max\", \"count\", \"stddev\", \"variance\". If resample is None, this is ignored."},{"name":"return_format","in":"query","required":false,"schema":{"$ref":"#/components/schemas/ReturnFormat","description":"The return format of the response","default":"json"},"description":"The return format of the response"},{"name":"download","in":"query","required":false,"schema":{"type":"boolean","description":"Whether to download the file or not","default":false,"title":"Download"},"description":"Whether to download the file or not"},{"name":"json_schema","in":"query","required":false,"schema":{"$ref":"#/components/schemas/JSONSchema","description":"The json schema of the response","default":"array-of-objects"},"description":"The json schema of the response"},{"name":"x-api-key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"API key for authentication (header)","title":"X-Api-Key"},"description":"API key for authentication (header)"}],"responses":{"200":{"description":"Successful response","content":{"application/json":{"schema":{"anyOf":[{"$ref":"#/components/schemas/QueryDatasetResponse"},{"$ref":"#/components/schemas/CSVResponse"}],"title":"Response Query Dataset V1 Datasets  Dataset Id  Query Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}}},"components":{"schemas":{"OrderBy":{"type":"string","enum":["asc","desc"],"title":"OrderBy"},"FilterOperator":{"type":"string","enum":["=","!=",">",">=","<","<=","in"],"title":"FilterOperator"},"ResampleFunction":{"type":"string","enum":["mean","sum","min","max","count","stddev","variance"],"title":"ResampleFunction"},"ReturnFormat":{"type":"string","enum":["json","csv"],"title":"ReturnFormat"},"JSONSchema":{"type":"string","enum":["array-of-objects","array-of-arrays"],"title":"JSONSchema"},"QueryDatasetResponse":{"properties":{"status_code":{"type":"integer","title":"Status Code"},"data":{"items":{"additionalProperties":true,"type":"object"},"type":"array","title":"Data"},"meta":{"$ref":"#/components/schemas/MetadataResponse"},"dataset_metadata":{"$ref":"#/components/schemas/DatasetResponse"}},"type":"object","required":["status_code","data","meta","dataset_metadata"],"title":"QueryDatasetResponse"},"MetadataResponse":{"properties":{"page":{"type":"integer","title":"Page"},"limit":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Limit"},"page_size":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Page Size"},"hasNextPage":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Hasnextpage"},"cursor":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Cursor"}},"type":"object","required":["page","limit","page_size","hasNextPage","cursor"],"title":"MetadataResponse"},"DatasetResponse":{"properties":{"id":{"type":"string","title":"Id"},"name":{"type":"string","title":"Name"},"description":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Description"},"earliest_available_time_utc":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Earliest Available Time Utc"},"latest_available_time_utc":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Latest Available Time Utc"},"source":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Source"},"last_checked_time_utc":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Last Checked Time Utc"},"primary_key_columns":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"null"}],"title":"Primary Key Columns"},"publish_time_column":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Publish Time Column"},"time_index_column":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Time Index Column"},"subseries_index_column":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Subseries Index Column"},"all_columns":{"anyOf":[{"items":{"$ref":"#/components/schemas/ColumnResponse"},"type":"array"},{"type":"null"}],"title":"All Columns"},"number_of_rows_approximate":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Number Of Rows Approximate"},"table_type":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Table Type"},"is_in_snowflake":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Is In Snowflake"},"data_frequency":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Data Frequency"},"source_url":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Source Url"},"publication_frequency":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Publication Frequency"},"is_published":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Is Published"},"created_at_utc":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Created At Utc"},"status":{"anyOf":[{"$ref":"#/components/schemas/DatasetStatusEnum"},{"type":"null"}]},"popularity_rank":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Popularity Rank"}},"type":"object","required":["id","name","description","earliest_available_time_utc","latest_available_time_utc","source","last_checked_time_utc","primary_key_columns","publish_time_column","time_index_column","subseries_index_column","all_columns","number_of_rows_approximate","table_type","is_in_snowflake","data_frequency","source_url","publication_frequency","is_published","created_at_utc","status"],"title":"DatasetResponse"},"ColumnResponse":{"properties":{"name":{"type":"string","title":"Name"},"type":{"type":"string","title":"Type"},"is_numeric":{"type":"boolean","title":"Is Numeric"},"is_date":{"type":"boolean","title":"Is Date","default":false},"is_datetime":{"type":"boolean","title":"Is Datetime"}},"type":"object","required":["name","type","is_numeric","is_datetime"],"title":"ColumnResponse"},"DatasetStatusEnum":{"type":"string","enum":["retired","active","deprecated"],"title":"DatasetStatusEnum"},"CSVResponse":{"properties":{"file":{"anyOf":[{"$ref":"#/components/schemas/FileResponseData"},{"type":"null"}],"description":"The CSV data as a bytes object, a string, or a StreamingResponse object."},"content_type":{"type":"string","title":"Content Type","description":"The content type of the response.","default":"text/csv"}},"type":"object","title":"CSVResponse"},"FileResponseData":{"properties":{"media_type":{"type":"string","title":"Media Type"},"content":{"anyOf":[{"type":"string","format":"binary"},{"type":"string"}],"title":"Content"}},"type":"object","required":["media_type","content"],"title":"FileResponseData"},"HTTPValidationError":{"properties":{"detail":{"items":{"$ref":"#/components/schemas/ValidationError"},"type":"array","title":"Detail"}},"type":"object","title":"HTTPValidationError"},"ValidationError":{"properties":{"loc":{"items":{"anyOf":[{"type":"string"},{"type":"integer"}]},"type":"array","title":"Location"},"msg":{"type":"string","title":"Message"},"type":{"type":"string","title":"Error Type"}},"type":"object","required":["loc","msg","type"],"title":"ValidationError"}}}}
```

## Query Dataset by column value

> Query a dataset by a column value\
> \
> This is a shortcut for \`/datasets/{dataset\_id}/query?filter\_column={filter\_column}\&filter\_value={filter\_value}\`

```json
{"openapi":"3.1.0","info":{"title":"Grid Status API","version":"1.3.0"},"servers":[{"url":"https://api.gridstatus.io/v1"}],"paths":{"/datasets/{dataset_id}/query/{filter_column_id}/{filter_value_path}":{"get":{"tags":["Query Data"],"summary":"Query Dataset by column value","description":"Query a dataset by a column value\n\nThis is a shortcut for `/datasets/{dataset_id}/query?filter_column={filter_column}&filter_value={filter_value}`","operationId":"query_dataset_column_value_v1_datasets__dataset_id__query__filter_column_id___filter_value_path__get","parameters":[{"name":"dataset_id","in":"path","required":true,"schema":{"type":"string","title":"Dataset Id"}},{"name":"filter_column_id","in":"path","required":true,"schema":{"type":"string","title":"Filter Column ID","description":"ID of the column to filter by"},"description":"ID of the column to filter by"},{"name":"filter_value_path","in":"path","required":true,"schema":{"type":"string","title":"Filter Value","description":"Value to filter by"},"description":"Value to filter by"},{"name":"api_key","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"API key for authentication (query)","title":"Api Key"},"description":"API key for authentication (query)"},{"name":"return_format","in":"query","required":false,"schema":{"$ref":"#/components/schemas/ReturnFormat","description":"The return format of the response","default":"json"},"description":"The return format of the response"},{"name":"download","in":"query","required":false,"schema":{"type":"boolean","description":"Whether to download the file or not","default":false,"title":"Download"},"description":"Whether to download the file or not"},{"name":"json_schema","in":"query","required":false,"schema":{"$ref":"#/components/schemas/JSONSchema","description":"The json schema of the response","default":"array-of-objects"},"description":"The json schema of the response"},{"name":"order","in":"query","required":false,"schema":{"anyOf":[{"$ref":"#/components/schemas/OrderBy"},{"type":"null"}],"description":"The order to order results by","default":"asc","title":"Order"},"description":"The order to order results by"},{"name":"filter_column","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"The column to filter results by","title":"Filter Column"},"description":"The column to filter results by"},{"name":"filter_value","in":"query","required":false,"schema":{"anyOf":[{"type":"integer"},{"type":"number"},{"type":"string"},{"type":"null"}],"description":"The value to filter results by","title":"Filter Value"},"description":"The value to filter results by"},{"name":"filter_operator","in":"query","required":false,"schema":{"anyOf":[{"$ref":"#/components/schemas/FilterOperator"},{"type":"null"}],"default":"=","title":"Filter Operator"}},{"name":"limit","in":"query","required":false,"schema":{"anyOf":[{"type":"integer"},{"type":"null"}],"description":"The maximum number of rows to return across all pages","title":"Limit"},"description":"The maximum number of rows to return across all pages"},{"name":"page","in":"query","required":false,"schema":{"type":"integer","description":"The page number of results to return","default":1,"title":"Page"},"description":"The page number of results to return"},{"name":"page_size","in":"query","required":false,"schema":{"anyOf":[{"type":"integer"},{"type":"null"}],"description":"The maximum number of rows to return in a single page","title":"Page Size"},"description":"The maximum number of rows to return in a single page"},{"name":"columns","in":"query","required":false,"schema":{"anyOf":[{"type":"array","items":{"type":"string"}},{"type":"string"},{"type":"null"}],"description":"Comma separated list of columns to return. Defaults to all columns.","title":"Columns"},"description":"Comma separated list of columns to return. Defaults to all columns."},{"name":"cursor","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Cursor"}},{"name":"timezone","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"The timezone to use when interpreting timezone naive timestamps, resampling to frequencies one day or more, and returning results. A value of `market`can be provided to return results in the timezone of the source ISO for the dataset. If `market` is specified and the dataset does not have a source ISO, the timezone will default to UTC for the query. When provided, columns in the `timezone` will be suffixed with `_local`.","default":"UTC","title":"Timezone"},"description":"The timezone to use when interpreting timezone naive timestamps, resampling to frequencies one day or more, and returning results. A value of `market`can be provided to return results in the timezone of the source ISO for the dataset. If `market` is specified and the dataset does not have a source ISO, the timezone will default to UTC for the query. When provided, columns in the `timezone` will be suffixed with `_local`."},{"name":"time","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"string","format":"date-time"},{"type":"null"}],"description":"The time to filter results. Cannot be used with start_time or end_time.\n\nPossible values:\n\n- 'latest': Fetches the most recently reported data point.\n\n- A specific timestamp string (ISO 8601 format): Returns records that were published at the provided timestamp.\n\n","title":"Time"},"description":"The time to filter results. Cannot be used with start_time or end_time.\n\nPossible values:\n\n- 'latest': Fetches the most recently reported data point.\n\n- A specific timestamp string (ISO 8601 format): Returns records that were published at the provided timestamp.\n\n"},{"name":"time_comparison","in":"query","required":false,"schema":{"anyOf":[{"enum":["=",">",">=","<","<="],"type":"string"},{"type":"null"}],"description":"The comparison operator to use when filtering by time.\n\nPossible values:\n\n- '=': Fetches the data at the exact time.\n\n- '>': Fetches the earliest data after the provided time.\n\n- '>=': Fetches the earliest data on or after the provided time.\n\n- '<': Fetches the latest data before the provided time.\n\n- '<=': Fetches the latest data on or before the provided time.\n\n","default":"=","title":"Time Comparison"},"description":"The comparison operator to use when filtering by time.\n\nPossible values:\n\n- '=': Fetches the data at the exact time.\n\n- '>': Fetches the earliest data after the provided time.\n\n- '>=': Fetches the earliest data on or after the provided time.\n\n- '<': Fetches the latest data before the provided time.\n\n- '<=': Fetches the latest data on or before the provided time.\n\n"},{"name":"start_time","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"string","format":"date-time"},{"type":"null"}],"description":"The start time to filter results using the dataset's time_index_column. Data on or after this time will be returned. Only applies to datasets with a time_index_column","title":"Start Time"},"description":"The start time to filter results using the dataset's time_index_column. Data on or after this time will be returned. Only applies to datasets with a time_index_column"},{"name":"end_time","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"string","format":"date-time"},{"type":"null"}],"description":"The end time to filter results using the dataset's time_index_column. Data before this time will be returned. Only applies to datasets with a time_index_column","title":"End Time"},"description":"The end time to filter results using the dataset's time_index_column. Data before this time will be returned. Only applies to datasets with a time_index_column"},{"name":"publish_time","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"string","format":"date-time"},{"type":"null"}],"description":"Controls the filtering based on the dataset's publish time.\n\nCannot be combined with publish_time_start or publish_time_end.Note: a dataset must have a time index column to use 'latest' or 'latest_before:' options.\n\nPossible values:\n\n- 'latest_report': Returns records only from the most recently published report.\n\n- 'latest': For any given timestamp, fetches the most recently reported data point associated with it.\n\n- A specific timestamp string (ISO 8601 format): Returns records that were published at the provided timestamp.\n\n- 'latest_before:<offset>': Return the most recent forecast for each operating time where publish_time <= operating_time + offset (e.g., 'latest_before:-6 hours').\n\n - 'latest_before': shorthand for 'latest_before:-0 hours'. Used to get the most recent forecast prior to each operating time. This is useful because some forecasts are published after the operating time they are forecasting for.\n\n- 'latest_before:<offset>@<HH:MM:SS>': Return the latest forecast published before the specified time on the offset day (e.g., 'latest_before:-1 day@10:00:00').\n\n - 'window':<offset>: Returns all forecasts for each operating time published between the specified offset from the operating time and the operating time. In other words, where operating_time + offset <= publish_time <= operating_time. (e.g., 'window:-6 hours').\n\n - 'window:<offset>@<HH:MM:SS>': Returns all forecasts for each operating time published between the specified time on the offset day from the operating time and the operating time (e.g., 'window:-1 day@10:00:00').\n\n- None: No filtering based on publish time.\n\n","title":"Publish Time"},"description":"Controls the filtering based on the dataset's publish time.\n\nCannot be combined with publish_time_start or publish_time_end.Note: a dataset must have a time index column to use 'latest' or 'latest_before:' options.\n\nPossible values:\n\n- 'latest_report': Returns records only from the most recently published report.\n\n- 'latest': For any given timestamp, fetches the most recently reported data point associated with it.\n\n- A specific timestamp string (ISO 8601 format): Returns records that were published at the provided timestamp.\n\n- 'latest_before:<offset>': Return the most recent forecast for each operating time where publish_time <= operating_time + offset (e.g., 'latest_before:-6 hours').\n\n - 'latest_before': shorthand for 'latest_before:-0 hours'. Used to get the most recent forecast prior to each operating time. This is useful because some forecasts are published after the operating time they are forecasting for.\n\n- 'latest_before:<offset>@<HH:MM:SS>': Return the latest forecast published before the specified time on the offset day (e.g., 'latest_before:-1 day@10:00:00').\n\n - 'window':<offset>: Returns all forecasts for each operating time published between the specified offset from the operating time and the operating time. In other words, where operating_time + offset <= publish_time <= operating_time. (e.g., 'window:-6 hours').\n\n - 'window:<offset>@<HH:MM:SS>': Returns all forecasts for each operating time published between the specified time on the offset day from the operating time and the operating time (e.g., 'window:-1 day@10:00:00').\n\n- None: No filtering based on publish time.\n\n"},{"name":"publish_time_start","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"string","format":"date-time"},{"type":"null"}],"description":"The start time to filter results using the dataset's publish_time_column. Data on or after this time will be returned up to the publish_time_end if provided. Only applies to datasets with a publish_time_column. Cannot be used with publish_time.","title":"Publish Time Start"},"description":"The start time to filter results using the dataset's publish_time_column. Data on or after this time will be returned up to the publish_time_end if provided. Only applies to datasets with a publish_time_column. Cannot be used with publish_time."},{"name":"publish_time_end","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"string","format":"date-time"},{"type":"null"}],"description":"The end time to filter results using the dataset's publish_index_column. Data before this time will be returned down the publish_time_start if provided. Only applies to datasets with a publish_time_column. Cannot be used with publish_time.","title":"Publish Time End"},"description":"The end time to filter results using the dataset's publish_index_column. Data before this time will be returned down the publish_time_start if provided. Only applies to datasets with a publish_time_column. Cannot be used with publish_time."},{"name":"resample_frequency","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"The frequency to resample the data to. Must be one of:\n\n- \"1 minute\"\n- \"5 minutes\"\n- \"10 minutes\"\n- \"15 minutes\"\n- \"1 hour\"\n- \"1 day\"\n- \"1 week\"\n- \"1 month\"\n- \"1 year\"\n\nWhen resampling_frequency is specified, start_time and end_time values must also be provided. The only exception to this is when querying datasets that have a publish time and the publish time is specified as a specific timestamp or 'latest_report'.\n\nAdditionally, the number of days of data that can be queried is limited based on the resample frequency. The maximum number of days of data that can be queried for each resample frequency is listed below. There is no limit on days for resample frequencies not listed below.\n\n- 1 minute: 31 days\n- 5 minutes: 100 days\n- 10 minutes: 120 days\n- 15 minutes: 180 days\n- 1 hour: 365 days\n- 1 day: 1825 days","title":"Resample Frequency"},"description":"The frequency to resample the data to. Must be one of:\n\n- \"1 minute\"\n- \"5 minutes\"\n- \"10 minutes\"\n- \"15 minutes\"\n- \"1 hour\"\n- \"1 day\"\n- \"1 week\"\n- \"1 month\"\n- \"1 year\"\n\nWhen resampling_frequency is specified, start_time and end_time values must also be provided. The only exception to this is when querying datasets that have a publish time and the publish time is specified as a specific timestamp or 'latest_report'.\n\nAdditionally, the number of days of data that can be queried is limited based on the resample frequency. The maximum number of days of data that can be queried for each resample frequency is listed below. There is no limit on days for resample frequencies not listed below.\n\n- 1 minute: 31 days\n- 5 minutes: 100 days\n- 10 minutes: 120 days\n- 15 minutes: 180 days\n- 1 hour: 365 days\n- 1 day: 1825 days"},{"name":"resample_by","in":"query","required":false,"schema":{"anyOf":[{"type":"array","items":{"type":"string"}},{"type":"string"},{"type":"null"}],"description":"A comma separated list of columns to group by before resampling. \n\n- When resampling, the data is always grouped by the time index column of the dataset.\n\n- If a value is provided for resample_by, the data will be grouped by the provided columns in addition to the time index column.\n\n- If the dataset has a subseries index and no value is provided for resample_by, the data will also be grouped by the subseries index column.\n\n- If the dataset has a publish time column and the publish_time parameter is not 'latest', the data will also be grouped by the publish time column.","title":"Resample By"},"description":"A comma separated list of columns to group by before resampling. \n\n- When resampling, the data is always grouped by the time index column of the dataset.\n\n- If a value is provided for resample_by, the data will be grouped by the provided columns in addition to the time index column.\n\n- If the dataset has a subseries index and no value is provided for resample_by, the data will also be grouped by the subseries index column.\n\n- If the dataset has a publish time column and the publish_time parameter is not 'latest', the data will also be grouped by the publish time column."},{"name":"resample_function","in":"query","required":false,"schema":{"anyOf":[{"$ref":"#/components/schemas/ResampleFunction"},{"type":"null"}],"description":"The function to use when resampling. Defaults to \"mean\". Possible values are \"mean\", \"sum\", \"min\", \"max\", \"count\", \"stddev\", \"variance\". If resample is None, this is ignored.","default":"mean","title":"Resample Function"},"description":"The function to use when resampling. Defaults to \"mean\". Possible values are \"mean\", \"sum\", \"min\", \"max\", \"count\", \"stddev\", \"variance\". If resample is None, this is ignored."},{"name":"x-api-key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"API key for authentication (header)","title":"X-Api-Key"},"description":"API key for authentication (header)"}],"responses":{"200":{"description":"Successful response","content":{"application/json":{"schema":{"anyOf":[{"$ref":"#/components/schemas/QueryDatasetResponse"},{"$ref":"#/components/schemas/CSVResponse"}],"title":"Response Query Dataset Column Value V1 Datasets  Dataset Id  Query  Filter Column Id   Filter Value Path  Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}}},"components":{"schemas":{"ReturnFormat":{"type":"string","enum":["json","csv"],"title":"ReturnFormat"},"JSONSchema":{"type":"string","enum":["array-of-objects","array-of-arrays"],"title":"JSONSchema"},"OrderBy":{"type":"string","enum":["asc","desc"],"title":"OrderBy"},"FilterOperator":{"type":"string","enum":["=","!=",">",">=","<","<=","in"],"title":"FilterOperator"},"ResampleFunction":{"type":"string","enum":["mean","sum","min","max","count","stddev","variance"],"title":"ResampleFunction"},"QueryDatasetResponse":{"properties":{"status_code":{"type":"integer","title":"Status Code"},"data":{"items":{"additionalProperties":true,"type":"object"},"type":"array","title":"Data"},"meta":{"$ref":"#/components/schemas/MetadataResponse"},"dataset_metadata":{"$ref":"#/components/schemas/DatasetResponse"}},"type":"object","required":["status_code","data","meta","dataset_metadata"],"title":"QueryDatasetResponse"},"MetadataResponse":{"properties":{"page":{"type":"integer","title":"Page"},"limit":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Limit"},"page_size":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Page Size"},"hasNextPage":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Hasnextpage"},"cursor":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Cursor"}},"type":"object","required":["page","limit","page_size","hasNextPage","cursor"],"title":"MetadataResponse"},"DatasetResponse":{"properties":{"id":{"type":"string","title":"Id"},"name":{"type":"string","title":"Name"},"description":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Description"},"earliest_available_time_utc":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Earliest Available Time Utc"},"latest_available_time_utc":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Latest Available Time Utc"},"source":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Source"},"last_checked_time_utc":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Last Checked Time Utc"},"primary_key_columns":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"null"}],"title":"Primary Key Columns"},"publish_time_column":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Publish Time Column"},"time_index_column":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Time Index Column"},"subseries_index_column":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Subseries Index Column"},"all_columns":{"anyOf":[{"items":{"$ref":"#/components/schemas/ColumnResponse"},"type":"array"},{"type":"null"}],"title":"All Columns"},"number_of_rows_approximate":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Number Of Rows Approximate"},"table_type":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Table Type"},"is_in_snowflake":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Is In Snowflake"},"data_frequency":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Data Frequency"},"source_url":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Source Url"},"publication_frequency":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Publication Frequency"},"is_published":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Is Published"},"created_at_utc":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Created At Utc"},"status":{"anyOf":[{"$ref":"#/components/schemas/DatasetStatusEnum"},{"type":"null"}]},"popularity_rank":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Popularity Rank"}},"type":"object","required":["id","name","description","earliest_available_time_utc","latest_available_time_utc","source","last_checked_time_utc","primary_key_columns","publish_time_column","time_index_column","subseries_index_column","all_columns","number_of_rows_approximate","table_type","is_in_snowflake","data_frequency","source_url","publication_frequency","is_published","created_at_utc","status"],"title":"DatasetResponse"},"ColumnResponse":{"properties":{"name":{"type":"string","title":"Name"},"type":{"type":"string","title":"Type"},"is_numeric":{"type":"boolean","title":"Is Numeric"},"is_date":{"type":"boolean","title":"Is Date","default":false},"is_datetime":{"type":"boolean","title":"Is Datetime"}},"type":"object","required":["name","type","is_numeric","is_datetime"],"title":"ColumnResponse"},"DatasetStatusEnum":{"type":"string","enum":["retired","active","deprecated"],"title":"DatasetStatusEnum"},"CSVResponse":{"properties":{"file":{"anyOf":[{"$ref":"#/components/schemas/FileResponseData"},{"type":"null"}],"description":"The CSV data as a bytes object, a string, or a StreamingResponse object."},"content_type":{"type":"string","title":"Content Type","description":"The content type of the response.","default":"text/csv"}},"type":"object","title":"CSVResponse"},"FileResponseData":{"properties":{"media_type":{"type":"string","title":"Media Type"},"content":{"anyOf":[{"type":"string","format":"binary"},{"type":"string"}],"title":"Content"}},"type":"object","required":["media_type","content"],"title":"FileResponseData"},"HTTPValidationError":{"properties":{"detail":{"items":{"$ref":"#/components/schemas/ValidationError"},"type":"array","title":"Detail"}},"type":"object","title":"HTTPValidationError"},"ValidationError":{"properties":{"loc":{"items":{"anyOf":[{"type":"string"},{"type":"integer"}]},"type":"array","title":"Location"},"msg":{"type":"string","title":"Message"},"type":{"type":"string","title":"Error Type"}},"type":"object","required":["loc","msg","type"],"title":"ValidationError"}}}}
```


# Dataset Updates

## Dataset Updates

> List all updates that have occurred in chronological order\
> for a specific dataset

```json
{"openapi":"3.1.0","info":{"title":"Grid Status API","version":"1.3.0"},"servers":[{"url":"https://api.gridstatus.io/v1"}],"paths":{"/dataset-updates/{dataset_id}":{"get":{"tags":["Dataset Updates"],"summary":"Dataset Updates","description":"List all updates that have occurred in chronological order\nfor a specific dataset","operationId":"dataset_updates_v1_dataset_updates__dataset_id__get","parameters":[{"name":"dataset_id","in":"path","required":true,"schema":{"type":"string","title":"Dataset Id"}},{"name":"api_key","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"API key for authentication (query)","title":"Api Key"},"description":"API key for authentication (query)"},{"name":"return_format","in":"query","required":false,"schema":{"$ref":"#/components/schemas/ReturnFormat","description":"The return format of the response","default":"json"},"description":"The return format of the response"},{"name":"download","in":"query","required":false,"schema":{"type":"boolean","description":"Whether to download the file or not","default":false,"title":"Download"},"description":"Whether to download the file or not"},{"name":"json_schema","in":"query","required":false,"schema":{"$ref":"#/components/schemas/JSONSchema","description":"The json schema of the response","default":"array-of-objects"},"description":"The json schema of the response"},{"name":"order","in":"query","required":false,"schema":{"anyOf":[{"$ref":"#/components/schemas/OrderBy"},{"type":"null"}],"description":"The order to order results by","default":"desc","title":"Order"},"description":"The order to order results by"},{"name":"limit","in":"query","required":false,"schema":{"anyOf":[{"type":"integer"},{"type":"null"}],"description":"The maximum number of rows to return across all pages","title":"Limit"},"description":"The maximum number of rows to return across all pages"},{"name":"x-api-key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"API key for authentication (header)","title":"X-Api-Key"},"description":"API key for authentication (header)"}],"responses":{"200":{"description":"Successful response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DatasetUpdatesResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}}},"components":{"schemas":{"ReturnFormat":{"type":"string","enum":["json","csv"],"title":"ReturnFormat"},"JSONSchema":{"type":"string","enum":["array-of-objects","array-of-arrays"],"title":"JSONSchema"},"OrderBy":{"type":"string","enum":["asc","desc"],"title":"OrderBy"},"DatasetUpdatesResponse":{"properties":{"status_code":{"type":"integer","title":"Status Code"},"data":{"items":{"$ref":"#/components/schemas/DatasetUpdateResponse"},"type":"array","title":"Data"},"meta":{"$ref":"#/components/schemas/MetadataResponse"}},"type":"object","required":["status_code","data","meta"],"title":"DatasetUpdatesResponse"},"DatasetUpdateResponse":{"properties":{"id":{"type":"string","title":"Id"},"dataset":{"type":"string","title":"Dataset"},"time_utc":{"type":"string","format":"date-time","title":"Time Utc"},"num_rows_updated":{"type":"integer","title":"Num Rows Updated"},"num_rows_inserted":{"type":"integer","title":"Num Rows Inserted"},"is_backfill":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Is Backfill"}},"type":"object","required":["id","dataset","time_utc","num_rows_updated","num_rows_inserted","is_backfill"],"title":"DatasetUpdateResponse"},"MetadataResponse":{"properties":{"page":{"type":"integer","title":"Page"},"limit":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Limit"},"page_size":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Page Size"},"hasNextPage":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Hasnextpage"},"cursor":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Cursor"}},"type":"object","required":["page","limit","page_size","hasNextPage","cursor"],"title":"MetadataResponse"},"HTTPValidationError":{"properties":{"detail":{"items":{"$ref":"#/components/schemas/ValidationError"},"type":"array","title":"Detail"}},"type":"object","title":"HTTPValidationError"},"ValidationError":{"properties":{"loc":{"items":{"anyOf":[{"type":"string"},{"type":"integer"}]},"type":"array","title":"Location"},"msg":{"type":"string","title":"Message"},"type":{"type":"string","title":"Error Type"}},"type":"object","required":["loc","msg","type"],"title":"ValidationError"}}}}
```


# Reports

## Get Daily Peak Report

> Get a daily peak report for the specified ISO on the specified date. If multiple peaks in LMP values are found in the Day Ahead Market data for a given zone, only data for the first peak will be returned.\
> \
> NOTE: You must be on a paid Grid Status plan to access this endpoint.

```json
{"openapi":"3.1.0","info":{"title":"Grid Status API","version":"1.3.0"},"servers":[{"url":"https://api.gridstatus.io/v1"}],"paths":{"/reports/daily_peak/{iso}":{"get":{"tags":["Reports"],"summary":"Get Daily Peak Report","description":"Get a daily peak report for the specified ISO on the specified date. If multiple peaks in LMP values are found in the Day Ahead Market data for a given zone, only data for the first peak will be returned.\n\nNOTE: You must be on a paid Grid Status plan to access this endpoint.","operationId":"get_daily_peak_report_v1_reports_daily_peak__iso__get","parameters":[{"name":"iso","in":"path","required":true,"schema":{"$ref":"#/components/schemas/ISOEnum","title":"ISO Name","description":"Name of the iso for which the report should be created"},"description":"Name of the iso for which the report should be created"},{"name":"date","in":"query","required":true,"schema":{"type":"string","format":"date","title":"date","description":"The date for which the report should be generated."},"description":"The date for which the report should be generated."},{"name":"api_key","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"API key for authentication (query)","title":"Api Key"},"description":"API key for authentication (query)"},{"name":"x-api-key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"API key for authentication (header)","title":"X-Api-Key"},"description":"API key for authentication (header)"}],"responses":{"200":{"description":"Successful response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PeakLoadReportResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}}},"components":{"schemas":{"ISOEnum":{"type":"string","enum":["CAISO","ERCOT","IESO","ISONE","MISO","NYISO","PJM","SPP"],"title":"ISOEnum"},"PeakLoadReportResponse":{"properties":{"ISO":{"type":"string","title":"Iso"},"market_date":{"type":"string","format":"date","title":"Market Date"},"timezone":{"type":"string","title":"Timezone"},"peak_dam_lmp":{"anyOf":[{"items":{"$ref":"#/components/schemas/PeakDamLmpResponse"},"type":"array"},{"type":"null"}],"title":"Peak Dam Lmp"},"peak_load":{"anyOf":[{"$ref":"#/components/schemas/PeakIntervalResponse"},{"type":"null"}]},"peak_net_load":{"anyOf":[{"$ref":"#/components/schemas/PeakIntervalResponse"},{"type":"null"}]}},"type":"object","required":["ISO","market_date","timezone"],"title":"PeakLoadReportResponse"},"PeakDamLmpResponse":{"additionalProperties":{"anyOf":[{"type":"number"},{"type":"string","format":"date-time"},{"type":"string"},{"type":"null"}]},"type":"object"},"PeakIntervalResponse":{"properties":{"interval_start_market":{"type":"string","format":"date-time","title":"Interval Start Market"},"interval_end_market":{"type":"string","format":"date-time","title":"Interval End Market"},"load":{"type":"number","title":"Load"},"net_load":{"type":"number","title":"Net Load"}},"additionalProperties":{"anyOf":[{"type":"number"},{"type":"null"}]},"type":"object","required":["interval_start_market","interval_end_market","load","net_load"],"title":"PeakIntervalResponse"},"HTTPValidationError":{"properties":{"detail":{"items":{"$ref":"#/components/schemas/ValidationError"},"type":"array","title":"Detail"}},"type":"object","title":"HTTPValidationError"},"ValidationError":{"properties":{"loc":{"items":{"anyOf":[{"type":"string"},{"type":"integer"}]},"type":"array","title":"Location"},"msg":{"type":"string","title":"Message"},"type":{"type":"string","title":"Error Type"}},"type":"object","required":["loc","msg","type"],"title":"ValidationError"}}}}
```


# API Usage

## Get Api Usage Endpoint

> Get API usage statistics and limits for the current user/organization.

```json
{"openapi":"3.1.0","info":{"title":"Grid Status API","version":"1.3.0"},"servers":[{"url":"https://api.gridstatus.io/v1"}],"paths":{"/api_usage":{"get":{"tags":["API Usage"],"summary":"Get Api Usage Endpoint","description":"Get API usage statistics and limits for the current user/organization.","operationId":"get_api_usage_endpoint_v1_api_usage_get","parameters":[{"name":"api_key","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"API key for authentication (query)","title":"Api Key"},"description":"API key for authentication (query)"},{"name":"x-api-key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"API key for authentication (header)","title":"X-Api-Key"},"description":"API key for authentication (header)"}],"responses":{"200":{"description":"Successful response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/APIUsageResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}}},"components":{"schemas":{"APIUsageResponse":{"properties":{"plan_name":{"type":"string","title":"Plan Name"},"limits":{"$ref":"#/components/schemas/APIUsageLimits"},"current_usage_period_start":{"type":"string","format":"date-time","title":"Current Usage Period Start"},"current_usage_period_end":{"type":"string","format":"date-time","title":"Current Usage Period End"},"current_period_usage":{"$ref":"#/components/schemas/CurrentPeriodUsage"}},"type":"object","required":["plan_name","limits","current_usage_period_start","current_usage_period_end","current_period_usage"],"title":"APIUsageResponse"},"APIUsageLimits":{"properties":{"api_rows_returned_limit":{"type":"integer","title":"Api Rows Returned Limit"},"api_requests_limit":{"type":"integer","title":"Api Requests Limit"},"api_rows_per_response_limit":{"type":"integer","title":"Api Rows Per Response Limit"},"per_second_api_rate_limit":{"type":"integer","title":"Per Second Api Rate Limit"},"per_minute_api_rate_limit":{"type":"integer","title":"Per Minute Api Rate Limit"},"per_hour_api_rate_limit":{"type":"integer","title":"Per Hour Api Rate Limit"}},"type":"object","required":["api_rows_returned_limit","api_requests_limit","api_rows_per_response_limit","per_second_api_rate_limit","per_minute_api_rate_limit","per_hour_api_rate_limit"],"title":"APIUsageLimits"},"CurrentPeriodUsage":{"properties":{"total_requests":{"type":"integer","title":"Total Requests"},"total_api_rows_returned":{"type":"integer","title":"Total Api Rows Returned"}},"type":"object","required":["total_requests","total_api_rows_returned"],"title":"CurrentPeriodUsage"},"HTTPValidationError":{"properties":{"detail":{"items":{"$ref":"#/components/schemas/ValidationError"},"type":"array","title":"Detail"}},"type":"object","title":"HTTPValidationError"},"ValidationError":{"properties":{"loc":{"items":{"anyOf":[{"type":"string"},{"type":"integer"}]},"type":"array","title":"Location"},"msg":{"type":"string","title":"Message"},"type":{"type":"string","title":"Error Type"}},"type":"object","required":["loc","msg","type"],"title":"ValidationError"}}}}
```


# CSV Exports

## Generate a presigned S3 URL for a bulk export file

> Return a time-limited presigned URL for a bulk export object on S3.\
> \
> Caller supplies dataset id, date, and (optionally) file type; the server\
> constructs the S3 key per the layout documented in\
> \`gitbook/bulk-csv-download/folder-structure.md\`.

```json
{"openapi":"3.1.0","info":{"title":"Grid Status API","version":"1.3.0"},"servers":[{"url":"https://api.gridstatus.io/v1"}],"paths":{"/csv-exports/{dataset_id}/{export_date}":{"get":{"tags":["CSV Exports"],"summary":"Generate a presigned S3 URL for a bulk export file","description":"Return a time-limited presigned URL for a bulk export object on S3.\n\nCaller supplies dataset id, date, and (optionally) file type; the server\nconstructs the S3 key per the layout documented in\n`gitbook/bulk-csv-download/folder-structure.md`.","operationId":"get_export_presigned_url_v1_csv_exports__dataset_id___export_date__get","parameters":[{"name":"dataset_id","in":"path","required":true,"schema":{"type":"string","title":"Dataset Id"}},{"name":"export_date","in":"path","required":true,"schema":{"type":"string","format":"date","description":"ISO 8601 date of the partition, e.g. `2025-03-14`.","title":"Export Date"},"description":"ISO 8601 date of the partition, e.g. `2025-03-14`."},{"name":"file_type","in":"query","required":false,"schema":{"const":"csv","type":"string","description":"File format. Currently only `csv` (gzipped) is available.","default":"csv","title":"File Type"},"description":"File format. Currently only `csv` (gzipped) is available."},{"name":"api_key","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"API key for authentication (query)","title":"Api Key"},"description":"API key for authentication (query)"},{"name":"x-api-key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"API key for authentication (header)","title":"X-Api-Key"},"description":"API key for authentication (header)"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PresignedUrlResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}}},"components":{"schemas":{"PresignedUrlResponse":{"properties":{"presigned_url":{"type":"string","title":"Presigned Url","description":"Time-limited HTTPS URL to download the requested file."},"expires_in_seconds":{"type":"integer","title":"Expires In Seconds","description":"Number of seconds the presigned URL is valid for."},"bucket":{"type":"string","title":"Bucket","description":"S3 bucket the object lives in."},"object_key":{"type":"string","title":"Object Key","description":"S3 object key the URL points to."}},"type":"object","required":["presigned_url","expires_in_seconds","bucket","object_key"],"title":"PresignedUrlResponse"},"HTTPValidationError":{"properties":{"detail":{"items":{"$ref":"#/components/schemas/ValidationError"},"type":"array","title":"Detail"}},"type":"object","title":"HTTPValidationError"},"ValidationError":{"properties":{"loc":{"items":{"anyOf":[{"type":"string"},{"type":"integer"}]},"type":"array","title":"Location"},"msg":{"type":"string","title":"Message"},"type":{"type":"string","title":"Error Type"}},"type":"object","required":["loc","msg","type"],"title":"ValidationError"}}}}
```

## List available bulk export files for a dataset

> List the per-day export files available on S3 for a dataset.\
> \
> Each entry includes the partition date, object size, and last-modified\
> timestamp; combine with \`GET /{dataset\_id}/{date}\` to fetch a presigned\
> URL for any specific file.

```json
{"openapi":"3.1.0","info":{"title":"Grid Status API","version":"1.3.0"},"servers":[{"url":"https://api.gridstatus.io/v1"}],"paths":{"/csv-exports/{dataset_id}":{"get":{"tags":["CSV Exports"],"summary":"List available bulk export files for a dataset","description":"List the per-day export files available on S3 for a dataset.\n\nEach entry includes the partition date, object size, and last-modified\ntimestamp; combine with `GET /{dataset_id}/{date}` to fetch a presigned\nURL for any specific file.","operationId":"list_dataset_exports_v1_csv_exports__dataset_id__get","parameters":[{"name":"dataset_id","in":"path","required":true,"schema":{"type":"string","title":"Dataset Id"}},{"name":"year","in":"query","required":false,"schema":{"anyOf":[{"type":"integer","maximum":9999,"minimum":1900},{"type":"null"}],"description":"Optional. Restrict the listing to a single year.","title":"Year"},"description":"Optional. Restrict the listing to a single year."},{"name":"month","in":"query","required":false,"schema":{"anyOf":[{"type":"integer","maximum":12,"minimum":1},{"type":"null"}],"description":"Optional. Restrict the listing to a single month. Requires `year`.","title":"Month"},"description":"Optional. Restrict the listing to a single month. Requires `year`."},{"name":"file_type","in":"query","required":false,"schema":{"const":"csv","type":"string","description":"File format to list. Currently only `csv` (gzipped).","default":"csv","title":"File Type"},"description":"File format to list. Currently only `csv` (gzipped)."},{"name":"api_key","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"API key for authentication (query)","title":"Api Key"},"description":"API key for authentication (query)"},{"name":"x-api-key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"API key for authentication (header)","title":"X-Api-Key"},"description":"API key for authentication (header)"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DatasetExportsListResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}}},"components":{"schemas":{"DatasetExportsListResponse":{"properties":{"dataset_id":{"type":"string","title":"Dataset Id"},"file_type":{"type":"string","const":"csv","title":"File Type"},"count":{"type":"integer","title":"Count"},"files":{"items":{"$ref":"#/components/schemas/DatasetExportFile"},"type":"array","title":"Files"}},"type":"object","required":["dataset_id","file_type","count","files"],"title":"DatasetExportsListResponse"},"DatasetExportFile":{"properties":{"date":{"type":"string","format":"date","title":"Date","description":"Partition date for this file."},"size_bytes":{"type":"integer","title":"Size Bytes","description":"Object size in bytes."},"last_modified":{"type":"string","format":"date-time","title":"Last Modified","description":"When the object was last written by the export pipeline."}},"type":"object","required":["date","size_bytes","last_modified"],"title":"DatasetExportFile"},"HTTPValidationError":{"properties":{"detail":{"items":{"$ref":"#/components/schemas/ValidationError"},"type":"array","title":"Detail"}},"type":"object","title":"HTTPValidationError"},"ValidationError":{"properties":{"loc":{"items":{"anyOf":[{"type":"string"},{"type":"integer"}]},"type":"array","title":"Location"},"msg":{"type":"string","title":"Message"},"type":{"type":"string","title":"Error Type"}},"type":"object","required":["loc","msg","type"],"title":"ValidationError"}}}}
```


# Constraints

## List Constraints

> Get a list of constraints with optional filtering by ISOs and a search term.\
> \
> Returns constraints where market\_id matches an item in the comma-separated\
> isos list and constraint\_name contains the search term. When sort\_order is\
> not specified and there is a search term, results are sorted by relevance\
> (shorter constraint\_names first). When sort\_order is not specified, there is no\
> search term, and include\_absolute\_costs is false, results are sorted by\
> latest\_seen\_utc descending (most recently seen first), then market\_id ascending,\
> then constraint\_name ascending. When include\_absolute\_costs is true and there is\
> no search term, results are sorted by rt\_absolute\_cost descending with nulls last.\
> \
> Use include\_absolute\_costs, include\_timestamps, and include\_dataset\_metadata to opt\
> into rt\_absolute\_cost/da\_absolute\_cost, GS timestamps, and pricing dataset metadata.

```json
{"openapi":"3.1.0","info":{"title":"Grid Status API","version":"1.3.0"},"servers":[{"url":"https://api.gridstatus.io/v1"}],"paths":{"/constraints":{"get":{"tags":["Constraints"],"summary":"List Constraints","description":"Get a list of constraints with optional filtering by ISOs and a search term.\n\nReturns constraints where market_id matches an item in the comma-separated\nisos list and constraint_name contains the search term. When sort_order is\nnot specified and there is a search term, results are sorted by relevance\n(shorter constraint_names first). When sort_order is not specified, there is no\nsearch term, and include_absolute_costs is false, results are sorted by\nlatest_seen_utc descending (most recently seen first), then market_id ascending,\nthen constraint_name ascending. When include_absolute_costs is true and there is\nno search term, results are sorted by rt_absolute_cost descending with nulls last.\n\nUse include_absolute_costs, include_timestamps, and include_dataset_metadata to opt\ninto rt_absolute_cost/da_absolute_cost, GS timestamps, and pricing dataset metadata.","operationId":"list_constraints_v1_constraints_get","parameters":[{"name":"include_absolute_costs","in":"query","required":false,"schema":{"type":"boolean","description":"When true, include rt_absolute_cost and da_absolute_cost on each constraint. Uses absolute_cost_start_time and absolute_cost_end_time when provided.","default":false,"title":"Include Absolute Costs"},"description":"When true, include rt_absolute_cost and da_absolute_cost on each constraint. Uses absolute_cost_start_time and absolute_cost_end_time when provided."},{"name":"include_timestamps","in":"query","required":false,"schema":{"type":"boolean","description":"When true, include gs_created_at_utc and gs_updated_at_utc.","default":false,"title":"Include Timestamps"},"description":"When true, include gs_created_at_utc and gs_updated_at_utc."},{"name":"include_dataset_metadata","in":"query","required":false,"schema":{"type":"boolean","description":"When true, include dataset_metadata with pricing dataset specs.","default":false,"title":"Include Dataset Metadata"},"description":"When true, include dataset_metadata with pricing dataset specs."},{"name":"absolute_cost_start_time","in":"query","required":false,"schema":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"description":"Optional lower bound for the absolute cost window. When set, include rows where time index >= absolute_cost_start_time. Only used when include_absolute_costs is true.","title":"Absolute Cost Start Time"},"description":"Optional lower bound for the absolute cost window. When set, include rows where time index >= absolute_cost_start_time. Only used when include_absolute_costs is true."},{"name":"absolute_cost_end_time","in":"query","required":false,"schema":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"description":"Optional upper bound for the absolute cost window. When set, include rows where time index < absolute_cost_end_time. Only used when include_absolute_costs is true.","title":"Absolute Cost End Time"},"description":"Optional upper bound for the absolute cost window. When set, include rows where time index < absolute_cost_end_time. Only used when include_absolute_costs is true."},{"name":"api_key","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"API key for authentication (query)","title":"Api Key"},"description":"API key for authentication (query)"},{"name":"isos","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Comma-separated list of market IDs to filter by","title":"Isos"},"description":"Comma-separated list of market IDs to filter by"},{"name":"active_after","in":"query","required":false,"schema":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"description":"Filter latest_seen_utc to be on or after this timestamp","title":"Active After"},"description":"Filter latest_seen_utc to be on or after this timestamp"},{"name":"limit","in":"query","required":false,"schema":{"anyOf":[{"type":"integer","maximum":100000,"minimum":0},{"type":"null"}],"description":"Maximum number of results to return (default: 10000)","default":10000,"title":"Limit"},"description":"Maximum number of results to return (default: 10000)"},{"name":"sort_order","in":"query","required":false,"schema":{"anyOf":[{"$ref":"#/components/schemas/OrderBy"},{"type":"null"}],"description":"Sort order: asc or desc. Defaults to desc when omitted.","title":"Sort Order"},"description":"Sort order: asc or desc. Defaults to desc when omitted."},{"name":"search","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Optional search term to filter by constraint_name","title":"Search"},"description":"Optional search term to filter by constraint_name"},{"name":"sort_column","in":"query","required":false,"schema":{"anyOf":[{"enum":["constraint_name","market_id","earliest_seen_utc","latest_seen_utc"],"type":"string"},{"type":"null"}],"description":"Column to sort by. Must be one of: constraint_name, market_id, earliest_seen_utc, latest_seen_utc","title":"Sort Column"},"description":"Column to sort by. Must be one of: constraint_name, market_id, earliest_seen_utc, latest_seen_utc"},{"name":"x-api-key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"API key for authentication (header)","title":"X-Api-Key"},"description":"API key for authentication (header)"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ConstraintsListResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}}},"components":{"schemas":{"OrderBy":{"type":"string","enum":["asc","desc"],"title":"OrderBy"},"ConstraintsListResponse":{"properties":{"data":{"items":{"$ref":"#/components/schemas/ConstraintResponse"},"type":"array","title":"Data"},"dataset_metadata":{"anyOf":[{"additionalProperties":{"additionalProperties":{"items":{"$ref":"#/components/schemas/ConstraintPricingDatasetSpecResponse"},"type":"array"},"type":"object"},"type":"object"},{"type":"null"}],"title":"Dataset Metadata"}},"type":"object","required":["data"],"title":"ConstraintsListResponse"},"ConstraintResponse":{"properties":{"gs_entity_id":{"type":"string","title":"Gs Entity Id"},"constraint_name":{"type":"string","title":"Constraint Name"},"market_id":{"type":"string","title":"Market Id"},"earliest_seen_utc":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Earliest Seen Utc"},"latest_seen_utc":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Latest Seen Utc"},"available_datasets":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"null"}],"title":"Available Datasets"},"rt_absolute_cost":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Rt Absolute Cost"},"da_absolute_cost":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Da Absolute Cost"},"gs_created_at_utc":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Gs Created At Utc"},"gs_updated_at_utc":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Gs Updated At Utc"}},"type":"object","required":["gs_entity_id","constraint_name","market_id","earliest_seen_utc","latest_seen_utc","available_datasets"],"title":"ConstraintResponse"},"ConstraintPricingDatasetSpecResponse":{"properties":{"dataset_id":{"type":"string","title":"Dataset Id"},"shadow_price_column":{"type":"string","title":"Shadow Price Column"}},"type":"object","required":["dataset_id","shadow_price_column"],"title":"ConstraintPricingDatasetSpecResponse"},"HTTPValidationError":{"properties":{"detail":{"items":{"$ref":"#/components/schemas/ValidationError"},"type":"array","title":"Detail"}},"type":"object","title":"HTTPValidationError"},"ValidationError":{"properties":{"loc":{"items":{"anyOf":[{"type":"string"},{"type":"integer"}]},"type":"array","title":"Location"},"msg":{"type":"string","title":"Message"},"type":{"type":"string","title":"Error Type"}},"type":"object","required":["loc","msg","type"],"title":"ValidationError"}}}}
```

## List Contingencies

> Get a list of contingencies with optional filtering by ISOs and a search term.\
> \
> Returns all rows and columns from the contingencies table where market\_id\
> matches an item in the comma-separated isos list and contingency\_name\
> contains the search term. When sort\_order is not specified and there is a\
> search term, results are sorted by relevance (shorter contingency\_names\
> first). When sort\_order is not specified and there is no search term,\
> results are sorted by latest\_seen\_utc descending (most recently seen first),\
> then market\_id ascending, then contingency\_name ascending for consistent\
> ordering.\
> \
> Args:\
> &#x20;   params: Query parameters (isos, search, active\_after, limit,\
> &#x20;       sort\_column, sort\_order)

```json
{"openapi":"3.1.0","info":{"title":"Grid Status API","version":"1.3.0"},"servers":[{"url":"https://api.gridstatus.io/v1"}],"paths":{"/constraints/contingencies":{"get":{"tags":["Constraints"],"summary":"List Contingencies","description":"Get a list of contingencies with optional filtering by ISOs and a search term.\n\nReturns all rows and columns from the contingencies table where market_id\nmatches an item in the comma-separated isos list and contingency_name\ncontains the search term. When sort_order is not specified and there is a\nsearch term, results are sorted by relevance (shorter contingency_names\nfirst). When sort_order is not specified and there is no search term,\nresults are sorted by latest_seen_utc descending (most recently seen first),\nthen market_id ascending, then contingency_name ascending for consistent\nordering.\n\nArgs:\n    params: Query parameters (isos, search, active_after, limit,\n        sort_column, sort_order)","operationId":"list_contingencies_v1_constraints_contingencies_get","parameters":[{"name":"api_key","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"API key for authentication (query)","title":"Api Key"},"description":"API key for authentication (query)"},{"name":"isos","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Comma-separated list of market IDs to filter by","title":"Isos"},"description":"Comma-separated list of market IDs to filter by"},{"name":"active_after","in":"query","required":false,"schema":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"description":"Filter latest_seen_utc to be on or after this timestamp","title":"Active After"},"description":"Filter latest_seen_utc to be on or after this timestamp"},{"name":"limit","in":"query","required":false,"schema":{"anyOf":[{"type":"integer","maximum":100000,"minimum":0},{"type":"null"}],"description":"Maximum number of results to return (default: 10000)","default":10000,"title":"Limit"},"description":"Maximum number of results to return (default: 10000)"},{"name":"sort_order","in":"query","required":false,"schema":{"anyOf":[{"$ref":"#/components/schemas/OrderBy"},{"type":"null"}],"description":"Sort order: asc or desc. Defaults to desc when omitted.","title":"Sort Order"},"description":"Sort order: asc or desc. Defaults to desc when omitted."},{"name":"search","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Optional search term to filter by contingency_name","title":"Search"},"description":"Optional search term to filter by contingency_name"},{"name":"sort_column","in":"query","required":false,"schema":{"anyOf":[{"enum":["contingency_name","market_id","earliest_seen_utc","latest_seen_utc"],"type":"string"},{"type":"null"}],"description":"Column to sort by. Must be one of: contingency_name, market_id, earliest_seen_utc, latest_seen_utc","title":"Sort Column"},"description":"Column to sort by. Must be one of: contingency_name, market_id, earliest_seen_utc, latest_seen_utc"},{"name":"x-api-key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"API key for authentication (header)","title":"X-Api-Key"},"description":"API key for authentication (header)"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/ContingencyListResponse"},"title":"Response List Contingencies V1 Constraints Contingencies Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}}},"components":{"schemas":{"OrderBy":{"type":"string","enum":["asc","desc"],"title":"OrderBy"},"ContingencyListResponse":{"properties":{"gs_entity_id":{"type":"string","title":"Gs Entity Id"},"contingency_name":{"type":"string","title":"Contingency Name"},"market_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Market Id"},"earliest_seen_utc":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Earliest Seen Utc"},"latest_seen_utc":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Latest Seen Utc"},"available_datasets":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"null"}],"title":"Available Datasets"},"gs_created_at_utc":{"type":"string","format":"date-time","title":"Gs Created At Utc"},"gs_updated_at_utc":{"type":"string","format":"date-time","title":"Gs Updated At Utc"}},"type":"object","required":["gs_entity_id","contingency_name","market_id","earliest_seen_utc","latest_seen_utc","available_datasets","gs_created_at_utc","gs_updated_at_utc"],"title":"ContingencyListResponse"},"HTTPValidationError":{"properties":{"detail":{"items":{"$ref":"#/components/schemas/ValidationError"},"type":"array","title":"Detail"}},"type":"object","title":"HTTPValidationError"},"ValidationError":{"properties":{"loc":{"items":{"anyOf":[{"type":"string"},{"type":"integer"}]},"type":"array","title":"Location"},"msg":{"type":"string","title":"Message"},"type":{"type":"string","title":"Error Type"}},"type":"object","required":["loc","msg","type"],"title":"ValidationError"}}}}
```

## List Shift Factors For Location

> Retrieve estimated shift factors for a pricing location.\
> \
> Queries ClickHouse \`\`linear\_estimated\_shift\_factors\`\` for the given\
> location, returning one row per \`\`constraint\_gs\_entity\_id\`\`. When multiple\
> source rows share the same constraint, \`\`estimated\_shift\_factor\`\` is\
> aggregated per \`\`aggregation\_function\`\` (mean, max, min, or median).\
> Optional \`\`contingency\_id\`\` restricts rows to a single contingency.\
> Optional \`\`dataset\_id\`\` filters on \`\`source\_dataset\`\`.\
> When \`\`exclude\_zeros\`\` is true, source rows with \`\`estimated\_shift\_factor\`\`\
> equal to zero are dropped before aggregating per constraint.

```json
{"openapi":"3.1.0","info":{"title":"Grid Status API","version":"1.3.0"},"servers":[{"url":"https://api.gridstatus.io/v1"}],"paths":{"/constraints/locations/{location_gs_entity_id}/shift-factors":{"get":{"tags":["Constraints"],"summary":"List Shift Factors For Location","description":"Retrieve estimated shift factors for a pricing location.\n\nQueries ClickHouse ``linear_estimated_shift_factors`` for the given\nlocation, returning one row per ``constraint_gs_entity_id``. When multiple\nsource rows share the same constraint, ``estimated_shift_factor`` is\naggregated per ``aggregation_function`` (mean, max, min, or median).\nOptional ``contingency_id`` restricts rows to a single contingency.\nOptional ``dataset_id`` filters on ``source_dataset``.\nWhen ``exclude_zeros`` is true, source rows with ``estimated_shift_factor``\nequal to zero are dropped before aggregating per constraint.","operationId":"list_shift_factors_for_location_v1_constraints_locations__location_gs_entity_id__shift_factors_get","parameters":[{"name":"location_gs_entity_id","in":"path","required":true,"schema":{"type":"string","title":"Location Gs Entity Id"}},{"name":"api_key","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"API key for authentication (query)","title":"Api Key"},"description":"API key for authentication (query)"},{"name":"contingency_id","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Contingency ID","description":"When set, only include rows with this contingency_gs_entity_id"},"description":"When set, only include rows with this contingency_gs_entity_id"},{"name":"dataset_id","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Dataset ID","description":"When set, only include rows with this source_dataset"},"description":"When set, only include rows with this source_dataset"},{"name":"exclude_zeros","in":"query","required":false,"schema":{"type":"boolean","title":"Exclude zeros","description":"When true, exclude rows where estimated_shift_factor is zero before aggregating each group","default":false},"description":"When true, exclude rows where estimated_shift_factor is zero before aggregating each group"},{"name":"aggregation_function","in":"query","required":false,"schema":{"enum":["mean","max","min","median"],"type":"string","title":"Aggregation function","description":"Function used to combine source rows in each group: mean, max, min, or median","default":"mean"},"description":"Function used to combine source rows in each group: mean, max, min, or median"},{"name":"x-api-key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"API key for authentication (header)","title":"X-Api-Key"},"description":"API key for authentication (header)"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/ShiftFactorConstraintResponse"},"title":"Response List Shift Factors For Location V1 Constraints Locations  Location Gs Entity Id  Shift Factors Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}}},"components":{"schemas":{"ShiftFactorConstraintResponse":{"properties":{"constraint_gs_entity_id":{"type":"string","title":"Constraint Gs Entity Id"},"estimated_shift_factor":{"type":"number","title":"Estimated Shift Factor"},"constraint":{"type":"string","title":"Constraint"}},"type":"object","required":["constraint_gs_entity_id","estimated_shift_factor","constraint"],"title":"ShiftFactorConstraintResponse","description":"Linear estimated shift factor aggregated per constraint for a location."},"HTTPValidationError":{"properties":{"detail":{"items":{"$ref":"#/components/schemas/ValidationError"},"type":"array","title":"Detail"}},"type":"object","title":"HTTPValidationError"},"ValidationError":{"properties":{"loc":{"items":{"anyOf":[{"type":"string"},{"type":"integer"}]},"type":"array","title":"Location"},"msg":{"type":"string","title":"Message"},"type":{"type":"string","title":"Error Type"}},"type":"object","required":["loc","msg","type"],"title":"ValidationError"}}}}
```

## List Constraint Costs For Location

> Get location-adjusted constraint costs over a time range.\
> \
> The endpoint computes absolute cost per constraint/contingency pair from the\
> specified constraint dataset in ClickHouse, then multiplies each by the\
> location's aggregated shift factor (mean) from\
> \`\`linear\_estimated\_shift\_factors\`\` for the same dataset.\
> For datasets without \`\`contingency\_gs\_entity\_id\`\`, costs are computed per\
> constraint and reused across that constraint's shift-factor contingency rows.\
> \
> Pass \`\`group\_by=constraint\`\` to roll contingency-grained rows up to one row\
> per constraint (sum of \`\`adjusted\_cost\`\`, mean \`\`shift\_factor\`\`; contingency\
> fields are null). \`\`absolute\_cost\`\` is summed when the dataset has a\
> contingency column; otherwise the shared per-constraint cost is kept once.

```json
{"openapi":"3.1.0","info":{"title":"Grid Status API","version":"1.3.0"},"servers":[{"url":"https://api.gridstatus.io/v1"}],"paths":{"/constraints/locations/{location_gs_entity_id}/constraint-costs":{"get":{"tags":["Constraints"],"summary":"List Constraint Costs For Location","description":"Get location-adjusted constraint costs over a time range.\n\nThe endpoint computes absolute cost per constraint/contingency pair from the\nspecified constraint dataset in ClickHouse, then multiplies each by the\nlocation's aggregated shift factor (mean) from\n``linear_estimated_shift_factors`` for the same dataset.\nFor datasets without ``contingency_gs_entity_id``, costs are computed per\nconstraint and reused across that constraint's shift-factor contingency rows.\n\nPass ``group_by=constraint`` to roll contingency-grained rows up to one row\nper constraint (sum of ``adjusted_cost``, mean ``shift_factor``; contingency\nfields are null). ``absolute_cost`` is summed when the dataset has a\ncontingency column; otherwise the shared per-constraint cost is kept once.","operationId":"list_constraint_costs_for_location_v1_constraints_locations__location_gs_entity_id__constraint_costs_get","parameters":[{"name":"location_gs_entity_id","in":"path","required":true,"schema":{"type":"string","title":"Location Gs Entity Id"}},{"name":"dataset_id","in":"query","required":true,"schema":{"type":"string","title":"Dataset Id"}},{"name":"start_time","in":"query","required":true,"schema":{"type":"string","format":"date-time","description":"Filter to rows where time index >= start_time (ISO 8601)","title":"Start Time"},"description":"Filter to rows where time index >= start_time (ISO 8601)"},{"name":"end_time","in":"query","required":true,"schema":{"type":"string","format":"date-time","description":"Filter to rows where time index < end_time (ISO 8601)","title":"End Time"},"description":"Filter to rows where time index < end_time (ISO 8601)"},{"name":"group_by","in":"query","required":false,"schema":{"enum":["constraint","constraint_contingency"],"type":"string","description":"Row grain. `constraint_contingency` (default) returns one row per constraint/contingency pair. `constraint` rolls those rows up to one row per constraint (sum of adjusted_cost, mean shift factor; absolute_cost summed only when the dataset has a contingency column).","default":"constraint_contingency","title":"Group By"},"description":"Row grain. `constraint_contingency` (default) returns one row per constraint/contingency pair. `constraint` rolls those rows up to one row per constraint (sum of adjusted_cost, mean shift factor; absolute_cost summed only when the dataset has a contingency column)."},{"name":"api_key","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"API key for authentication (query)","title":"Api Key"},"description":"API key for authentication (query)"},{"name":"x-api-key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"API key for authentication (header)","title":"X-Api-Key"},"description":"API key for authentication (header)"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/LocationConstraintCostResponse"},"title":"Response List Constraint Costs For Location V1 Constraints Locations  Location Gs Entity Id  Constraint Costs Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}}},"components":{"schemas":{"LocationConstraintCostResponse":{"properties":{"constraint_gs_entity_id":{"type":"string","title":"Constraint Gs Entity Id"},"constraint_name":{"type":"string","title":"Constraint Name"},"contingency_gs_entity_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Contingency Gs Entity Id"},"contingency_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Contingency Name"},"shift_factor":{"type":"number","title":"Shift Factor"},"absolute_cost":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Absolute Cost"},"adjusted_cost":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Adjusted Cost"}},"type":"object","required":["constraint_gs_entity_id","constraint_name","contingency_gs_entity_id","contingency_name","shift_factor","absolute_cost","adjusted_cost"],"title":"LocationConstraintCostResponse","description":"Constraint costs adjusted by a location's shift factor.\n\nDefault grain is constraint + contingency. When the endpoint is called with\n``group_by=constraint``, contingency fields are null and costs/shift factors\nare rolled up across contingencies for each constraint. ``adjusted_cost`` is\nalways summed; ``absolute_cost`` is summed only when the underlying dataset has\na contingency column (otherwise the shared per-constraint cost is kept once)."},"HTTPValidationError":{"properties":{"detail":{"items":{"$ref":"#/components/schemas/ValidationError"},"type":"array","title":"Detail"}},"type":"object","title":"HTTPValidationError"},"ValidationError":{"properties":{"loc":{"items":{"anyOf":[{"type":"string"},{"type":"integer"}]},"type":"array","title":"Location"},"msg":{"type":"string","title":"Message"},"type":{"type":"string","title":"Error Type"}},"type":"object","required":["loc","msg","type"],"title":"ValidationError"}}}}
```

## List Shift Factors

> Retrieve estimated shift factors for a constraint.\
> \
> Queries ClickHouse \`\`linear\_estimated\_shift\_factors\`\` for the given\
> constraint, returning one row per \`\`location\_gs\_entity\_id\`\`. When multiple\
> source rows share the same location, \`\`estimated\_shift\_factor\`\` is\
> aggregated per \`\`aggregation\_function\`\` (mean, max, min, or median).\
> Optional \`\`contingency\_id\`\` restricts rows to a single contingency.\
> Optional \`\`dataset\_id\`\` filters on \`\`source\_dataset\`\`.\
> When \`\`exclude\_zeros\`\` is true, source rows with \`\`estimated\_shift\_factor\`\`\
> equal to zero are dropped before aggregating per location.

```json
{"openapi":"3.1.0","info":{"title":"Grid Status API","version":"1.3.0"},"servers":[{"url":"https://api.gridstatus.io/v1"}],"paths":{"/constraints/{constraint_id}/shift-factors":{"get":{"tags":["Constraints"],"summary":"List Shift Factors","description":"Retrieve estimated shift factors for a constraint.\n\nQueries ClickHouse ``linear_estimated_shift_factors`` for the given\nconstraint, returning one row per ``location_gs_entity_id``. When multiple\nsource rows share the same location, ``estimated_shift_factor`` is\naggregated per ``aggregation_function`` (mean, max, min, or median).\nOptional ``contingency_id`` restricts rows to a single contingency.\nOptional ``dataset_id`` filters on ``source_dataset``.\nWhen ``exclude_zeros`` is true, source rows with ``estimated_shift_factor``\nequal to zero are dropped before aggregating per location.","operationId":"list_shift_factors_v1_constraints__constraint_id__shift_factors_get","parameters":[{"name":"constraint_id","in":"path","required":true,"schema":{"type":"string","title":"Constraint ID","description":"GS entity ID of the constraint to get shift factors for"},"description":"GS entity ID of the constraint to get shift factors for"},{"name":"api_key","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"API key for authentication (query)","title":"Api Key"},"description":"API key for authentication (query)"},{"name":"contingency_id","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Contingency ID","description":"When set, only include rows with this contingency_gs_entity_id"},"description":"When set, only include rows with this contingency_gs_entity_id"},{"name":"dataset_id","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Dataset ID","description":"When set, only include rows with this source_dataset"},"description":"When set, only include rows with this source_dataset"},{"name":"exclude_zeros","in":"query","required":false,"schema":{"type":"boolean","title":"Exclude zeros","description":"When true, exclude rows where estimated_shift_factor is zero before aggregating each group","default":false},"description":"When true, exclude rows where estimated_shift_factor is zero before aggregating each group"},{"name":"aggregation_function","in":"query","required":false,"schema":{"enum":["mean","max","min","median"],"type":"string","title":"Aggregation function","description":"Function used to combine source rows in each group: mean, max, min, or median","default":"mean"},"description":"Function used to combine source rows in each group: mean, max, min, or median"},{"name":"x-api-key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"API key for authentication (header)","title":"X-Api-Key"},"description":"API key for authentication (header)"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/ShiftFactorLocationResponse"},"title":"Response List Shift Factors V1 Constraints  Constraint Id  Shift Factors Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}}},"components":{"schemas":{"ShiftFactorLocationResponse":{"properties":{"location_gs_entity_id":{"type":"string","title":"Location Gs Entity Id"},"estimated_shift_factor":{"type":"number","title":"Estimated Shift Factor"},"location":{"type":"string","title":"Location"}},"type":"object","required":["location_gs_entity_id","estimated_shift_factor","location"],"title":"ShiftFactorLocationResponse","description":"Linear estimated shift factor aggregated per location for a constraint."},"HTTPValidationError":{"properties":{"detail":{"items":{"$ref":"#/components/schemas/ValidationError"},"type":"array","title":"Detail"}},"type":"object","title":"HTTPValidationError"},"ValidationError":{"properties":{"loc":{"items":{"anyOf":[{"type":"string"},{"type":"integer"}]},"type":"array","title":"Location"},"msg":{"type":"string","title":"Message"},"type":{"type":"string","title":"Error Type"}},"type":"object","required":["loc","msg","type"],"title":"ValidationError"}}}}
```

## Get Constraint Location

> Retrieve start/end substation coordinates for a constraint.\
> \
> Returns nullable \`\`start\`\` and \`\`end\`\` lat/lon from the market's constraint\
> geometry table. Markets without a geometry table return 400. Unknown constraint\
> ids return 404.

```json
{"openapi":"3.1.0","info":{"title":"Grid Status API","version":"1.3.0"},"servers":[{"url":"https://api.gridstatus.io/v1"}],"paths":{"/constraints/{constraint_id}/location":{"get":{"tags":["Constraints"],"summary":"Get Constraint Location","description":"Retrieve start/end substation coordinates for a constraint.\n\nReturns nullable ``start`` and ``end`` lat/lon from the market's constraint\ngeometry table. Markets without a geometry table return 400. Unknown constraint\nids return 404.","operationId":"get_constraint_location_v1_constraints__constraint_id__location_get","parameters":[{"name":"constraint_id","in":"path","required":true,"schema":{"type":"string","title":"Constraint ID","description":"GS entity ID of the constraint to get facility location for"},"description":"GS entity ID of the constraint to get facility location for"},{"name":"api_key","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"API key for authentication (query)","title":"Api Key"},"description":"API key for authentication (query)"},{"name":"x-api-key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"API key for authentication (header)","title":"X-Api-Key"},"description":"API key for authentication (header)"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ConstraintLocationResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}}},"components":{"schemas":{"ConstraintLocationResponse":{"properties":{"constraint_gs_entity_id":{"type":"string","title":"Constraint Gs Entity Id"},"constraint_name":{"type":"string","title":"Constraint Name"},"start":{"anyOf":[{"$ref":"#/components/schemas/SubstationLocation"},{"type":"null"}]},"end":{"anyOf":[{"$ref":"#/components/schemas/SubstationLocation"},{"type":"null"}]}},"type":"object","required":["constraint_gs_entity_id","constraint_name"],"title":"ConstraintLocationResponse","description":"Start/end substation coordinates for a constraint.\n\nEither endpoint may be null when that constraint has no mapped coords.\nMarkets without a geometry table are rejected by the endpoint (400)."},"SubstationLocation":{"properties":{"latitude":{"type":"number","title":"Latitude"},"longitude":{"type":"number","title":"Longitude"},"name":{"type":"string","title":"Name"}},"type":"object","required":["latitude","longitude","name"],"title":"SubstationLocation","description":"Lat/lon and display name for a substation."},"HTTPValidationError":{"properties":{"detail":{"items":{"$ref":"#/components/schemas/ValidationError"},"type":"array","title":"Detail"}},"type":"object","title":"HTTPValidationError"},"ValidationError":{"properties":{"loc":{"items":{"anyOf":[{"type":"string"},{"type":"integer"}]},"type":"array","title":"Location"},"msg":{"type":"string","title":"Message"},"type":{"type":"string","title":"Error Type"}},"type":"object","required":["loc","msg","type"],"title":"ValidationError"}}}}
```

## List Constraint Binding Rows

> Get binding rows for a dataset with constraint display names.

```json
{"openapi":"3.1.0","info":{"title":"Grid Status API","version":"1.3.0"},"servers":[{"url":"https://api.gridstatus.io/v1"}],"paths":{"/constraints/binding":{"get":{"tags":["Constraints"],"summary":"List Constraint Binding Rows","description":"Get binding rows for a dataset with constraint display names.","operationId":"list_constraint_binding_rows_v1_constraints_binding_get","parameters":[{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":100000,"minimum":1,"description":"Maximum number of rows to return.","default":50000,"title":"Limit"},"description":"Maximum number of rows to return."},{"name":"api_key","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"API key for authentication (query)","title":"Api Key"},"description":"API key for authentication (query)"},{"name":"dataset_id","in":"query","required":true,"schema":{"type":"string","title":"Dataset Id"}},{"name":"start_time","in":"query","required":false,"schema":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"description":"Filter to rows where time index >= start_time (ISO 8601)","title":"Start Time"},"description":"Filter to rows where time index >= start_time (ISO 8601)"},{"name":"end_time","in":"query","required":false,"schema":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"description":"Filter to rows where time index < end_time (ISO 8601 timestamp)","title":"End Time"},"description":"Filter to rows where time index < end_time (ISO 8601 timestamp)"},{"name":"price_threshold","in":"query","required":false,"schema":{"anyOf":[{"type":"number"},{"type":"null"}],"description":"Optional threshold. When set, only include rows where ABS(configured shadow price column) > price_threshold.","title":"Price Threshold"},"description":"Optional threshold. When set, only include rows where ABS(configured shadow price column) > price_threshold."},{"name":"x-api-key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"API key for authentication (header)","title":"X-Api-Key"},"description":"API key for authentication (header)"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"array","items":{"type":"object","additionalProperties":true},"title":"Response List Constraint Binding Rows V1 Constraints Binding Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}}},"components":{"schemas":{"HTTPValidationError":{"properties":{"detail":{"items":{"$ref":"#/components/schemas/ValidationError"},"type":"array","title":"Detail"}},"type":"object","title":"HTTPValidationError"},"ValidationError":{"properties":{"loc":{"items":{"anyOf":[{"type":"string"},{"type":"integer"}]},"type":"array","title":"Location"},"msg":{"type":"string","title":"Message"},"type":{"type":"string","title":"Error Type"}},"type":"object","required":["loc","msg","type"],"title":"ValidationError"}}}}
```

## List Binding Constraints With Locations

> Get unique binding constraints for a dataset/time window with locations.\
> \
> Scans binding observations for \`\`dataset\_id\`\` in \`\`\[start\_time, end\_time)\`\`,\
> collapses peak-|shadow| per (constraint, interval), keeps the top\
> \`\`limit\`\` constraints by peak |shadow|, joins facility coordinates and\
> contingency identity/names, and returns one object per constraint with\
> nested observations, ordered by that ranking.

```json
{"openapi":"3.1.0","info":{"title":"Grid Status API","version":"1.3.0"},"servers":[{"url":"https://api.gridstatus.io/v1"}],"paths":{"/constraints/binding/locations":{"get":{"tags":["Constraints"],"summary":"List Binding Constraints With Locations","description":"Get unique binding constraints for a dataset/time window with locations.\n\nScans binding observations for ``dataset_id`` in ``[start_time, end_time)``,\ncollapses peak-|shadow| per (constraint, interval), keeps the top\n``limit`` constraints by peak |shadow|, joins facility coordinates and\ncontingency identity/names, and returns one object per constraint with\nnested observations, ordered by that ranking.","operationId":"list_binding_constraints_with_locations_v1_constraints_binding_locations_get","parameters":[{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":100000,"minimum":1,"description":"Maximum number of unique binding constraints to return (all intervals for each are included).","default":50000,"title":"Limit"},"description":"Maximum number of unique binding constraints to return (all intervals for each are included)."},{"name":"api_key","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"API key for authentication (query)","title":"Api Key"},"description":"API key for authentication (query)"},{"name":"dataset_id","in":"query","required":true,"schema":{"type":"string","title":"Dataset Id"}},{"name":"start_time","in":"query","required":true,"schema":{"type":"string","format":"date-time","description":"Filter to rows where time index >= start_time (ISO 8601)","title":"Start Time"},"description":"Filter to rows where time index >= start_time (ISO 8601)"},{"name":"end_time","in":"query","required":true,"schema":{"type":"string","format":"date-time","description":"Filter to rows where time index < end_time (ISO 8601 timestamp)","title":"End Time"},"description":"Filter to rows where time index < end_time (ISO 8601 timestamp)"},{"name":"x-api-key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"API key for authentication (header)","title":"X-Api-Key"},"description":"API key for authentication (header)"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BindingConstraintsWithLocationsResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}}},"components":{"schemas":{"BindingConstraintsWithLocationsResponse":{"properties":{"constraints":{"items":{"$ref":"#/components/schemas/BindingConstraintWithLocationResponse"},"type":"array","title":"Constraints"}},"type":"object","required":["constraints"],"title":"BindingConstraintsWithLocationsResponse","description":"Binding constraints for a dataset/time window, merged with substations."},"BindingConstraintWithLocationResponse":{"properties":{"constraint_gs_entity_id":{"type":"string","title":"Constraint Gs Entity Id"},"constraint_name":{"type":"string","title":"Constraint Name"},"start":{"anyOf":[{"$ref":"#/components/schemas/SubstationLocation"},{"type":"null"}]},"end":{"anyOf":[{"$ref":"#/components/schemas/SubstationLocation"},{"type":"null"}]},"observations":{"items":{"$ref":"#/components/schemas/BindingConstraintObservation"},"type":"array","title":"Observations"}},"type":"object","required":["constraint_gs_entity_id","constraint_name","observations"],"title":"BindingConstraintWithLocationResponse","description":"A unique binding constraint with substation coords and interval observations.\n\n``observations`` lists every binding interval (and its shadow price) in the\nquery window so clients can filter to a single interval or day-peak price\nwithout a second request."},"SubstationLocation":{"properties":{"latitude":{"type":"number","title":"Latitude"},"longitude":{"type":"number","title":"Longitude"},"name":{"type":"string","title":"Name"}},"type":"object","required":["latitude","longitude","name"],"title":"SubstationLocation","description":"Lat/lon and display name for a substation."},"BindingConstraintObservation":{"properties":{"interval_start_utc":{"type":"string","format":"date-time","title":"Interval Start Utc"},"shadow_price":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Shadow Price"},"contingency_gs_entity_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Contingency Gs Entity Id"},"contingency_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Contingency Name"}},"type":"object","required":["interval_start_utc"],"title":"BindingConstraintObservation","description":"One binding observation for a constraint in the query window."},"HTTPValidationError":{"properties":{"detail":{"items":{"$ref":"#/components/schemas/ValidationError"},"type":"array","title":"Detail"}},"type":"object","title":"HTTPValidationError"},"ValidationError":{"properties":{"loc":{"items":{"anyOf":[{"type":"string"},{"type":"integer"}]},"type":"array","title":"Location"},"msg":{"type":"string","title":"Message"},"type":{"type":"string","title":"Error Type"}},"type":"object","required":["loc","msg","type"],"title":"ValidationError"}}}}
```

## List Constraint Binding Intervals By Hour

> Get filtered binding interval counts grouped by hour-of-day.

```json
{"openapi":"3.1.0","info":{"title":"Grid Status API","version":"1.3.0"},"servers":[{"url":"https://api.gridstatus.io/v1"}],"paths":{"/constraints/{constraint_id}/binding_intervals_by_hour":{"get":{"tags":["Constraints"],"summary":"List Constraint Binding Intervals By Hour","description":"Get filtered binding interval counts grouped by hour-of-day.","operationId":"list_constraint_binding_intervals_by_hour_v1_constraints__constraint_id__binding_intervals_by_hour_get","parameters":[{"name":"constraint_id","in":"path","required":true,"schema":{"type":"string","title":"Constraint ID","description":"GS entity ID of the constraint to query"},"description":"GS entity ID of the constraint to query"},{"name":"api_key","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"API key for authentication (query)","title":"Api Key"},"description":"API key for authentication (query)"},{"name":"dataset_id","in":"query","required":true,"schema":{"type":"string","title":"Dataset Id"}},{"name":"timezone","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Optional IANA timezone (e.g. America/New_York). When provided, buckets are computed in this timezone.","title":"Timezone"},"description":"Optional IANA timezone (e.g. America/New_York). When provided, buckets are computed in this timezone."},{"name":"start_time","in":"query","required":false,"schema":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"description":"Filter to rows where time index >= start_time (ISO 8601)","title":"Start Time"},"description":"Filter to rows where time index >= start_time (ISO 8601)"},{"name":"end_time","in":"query","required":false,"schema":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"description":"Filter to rows where time index < end_time (ISO 8601)","title":"End Time"},"description":"Filter to rows where time index < end_time (ISO 8601)"},{"name":"price_threshold","in":"query","required":false,"schema":{"anyOf":[{"type":"number"},{"type":"null"}],"description":"Optional threshold. When set, only include rows where ABS(configured shadow price column) > price_threshold.","title":"Price Threshold"},"description":"Optional threshold. When set, only include rows where ABS(configured shadow price column) > price_threshold."},{"name":"contingency_id","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Optional contingency GS entity ID filter.","title":"Contingency Id"},"description":"Optional contingency GS entity ID filter."},{"name":"x-api-key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"API key for authentication (header)","title":"X-Api-Key"},"description":"API key for authentication (header)"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/ConstraintBindingHourCountResponse"},"title":"Response List Constraint Binding Intervals By Hour V1 Constraints  Constraint Id  Binding Intervals By Hour Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}}},"components":{"schemas":{"ConstraintBindingHourCountResponse":{"properties":{"hour":{"type":"integer","title":"Hour"},"count":{"type":"integer","title":"Count"}},"type":"object","required":["hour","count"],"title":"ConstraintBindingHourCountResponse","description":"Count of filtered binding rows by local hour (requested timezone or UTC)."},"HTTPValidationError":{"properties":{"detail":{"items":{"$ref":"#/components/schemas/ValidationError"},"type":"array","title":"Detail"}},"type":"object","title":"HTTPValidationError"},"ValidationError":{"properties":{"loc":{"items":{"anyOf":[{"type":"string"},{"type":"integer"}]},"type":"array","title":"Location"},"msg":{"type":"string","title":"Message"},"type":{"type":"string","title":"Error Type"}},"type":"object","required":["loc","msg","type"],"title":"ValidationError"}}}}
```

## List Constraint Stats By Interval

> Get per-interval count, shadow-price summary stats, and absolute cost.

```json
{"openapi":"3.1.0","info":{"title":"Grid Status API","version":"1.3.0"},"servers":[{"url":"https://api.gridstatus.io/v1"}],"paths":{"/constraints/{constraint_id}/stats":{"get":{"tags":["Constraints"],"summary":"List Constraint Stats By Interval","description":"Get per-interval count, shadow-price summary stats, and absolute cost.","operationId":"list_constraint_stats_by_interval_v1_constraints__constraint_id__stats_get","parameters":[{"name":"constraint_id","in":"path","required":true,"schema":{"type":"string","title":"Constraint ID","description":"GS entity ID of the constraint to query"},"description":"GS entity ID of the constraint to query"},{"name":"aggregation_period","in":"query","required":true,"schema":{"enum":["hour","day","month","year"],"type":"string","description":"Aggregation bucket size. One of \"hour\", \"day\", \"month\", \"year\".","title":"Aggregation Period"},"description":"Aggregation bucket size. One of \"hour\", \"day\", \"month\", \"year\"."},{"name":"api_key","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"API key for authentication (query)","title":"Api Key"},"description":"API key for authentication (query)"},{"name":"dataset_id","in":"query","required":true,"schema":{"type":"string","title":"Dataset Id"}},{"name":"timezone","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Optional IANA timezone (e.g. America/New_York). When provided, buckets are computed in this timezone.","title":"Timezone"},"description":"Optional IANA timezone (e.g. America/New_York). When provided, buckets are computed in this timezone."},{"name":"start_time","in":"query","required":false,"schema":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"description":"Filter to rows where time index >= start_time (ISO 8601)","title":"Start Time"},"description":"Filter to rows where time index >= start_time (ISO 8601)"},{"name":"end_time","in":"query","required":false,"schema":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"description":"Filter to rows where time index < end_time (ISO 8601)","title":"End Time"},"description":"Filter to rows where time index < end_time (ISO 8601)"},{"name":"price_threshold","in":"query","required":false,"schema":{"anyOf":[{"type":"number"},{"type":"null"}],"description":"Optional threshold. When set, only include rows where ABS(configured shadow price column) > price_threshold.","title":"Price Threshold"},"description":"Optional threshold. When set, only include rows where ABS(configured shadow price column) > price_threshold."},{"name":"contingency_id","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Optional contingency GS entity ID filter.","title":"Contingency Id"},"description":"Optional contingency GS entity ID filter."},{"name":"x-api-key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"API key for authentication (header)","title":"X-Api-Key"},"description":"API key for authentication (header)"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/ConstraintStatsIntervalResponse"},"title":"Response List Constraint Stats By Interval V1 Constraints  Constraint Id  Stats Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}}},"components":{"schemas":{"ConstraintStatsIntervalResponse":{"properties":{"interval_start_utc":{"type":"string","format":"date-time","title":"Interval Start Utc"},"binding_intervals":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Binding Intervals"},"shadow_price_min":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Shadow Price Min"},"shadow_price_mean":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Shadow Price Mean"},"shadow_price_median":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Shadow Price Median"},"shadow_price_max":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Shadow Price Max"},"absolute_cost":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Absolute Cost"}},"type":"object","required":["interval_start_utc","binding_intervals","shadow_price_min","shadow_price_mean","shadow_price_median","shadow_price_max","absolute_cost"],"title":"ConstraintStatsIntervalResponse","description":"Per-interval aggregate stats for filtered constraint rows."},"HTTPValidationError":{"properties":{"detail":{"items":{"$ref":"#/components/schemas/ValidationError"},"type":"array","title":"Detail"}},"type":"object","title":"HTTPValidationError"},"ValidationError":{"properties":{"loc":{"items":{"anyOf":[{"type":"string"},{"type":"integer"}]},"type":"array","title":"Location"},"msg":{"type":"string","title":"Message"},"type":{"type":"string","title":"Error Type"}},"type":"object","required":["loc","msg","type"],"title":"ValidationError"}}}}
```

## List Constraint Binding Counts By Period

> Summarize unique binding constraints per UTC period for a dataset.

```json
{"openapi":"3.1.0","info":{"title":"Grid Status API","version":"1.3.0"},"servers":[{"url":"https://api.gridstatus.io/v1"}],"paths":{"/constraints/binding/counts":{"get":{"tags":["Constraints"],"summary":"List Constraint Binding Counts By Period","description":"Summarize unique binding constraints per UTC period for a dataset.","operationId":"list_constraint_binding_counts_by_period_v1_constraints_binding_counts_get","parameters":[{"name":"aggregation_period","in":"query","required":false,"schema":{"enum":["hour","day","month","year"],"type":"string","description":"UTC aggregation period for grouping counts. Supported values: hour, day, month, year.","default":"hour","title":"Aggregation Period"},"description":"UTC aggregation period for grouping counts. Supported values: hour, day, month, year."},{"name":"api_key","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"API key for authentication (query)","title":"Api Key"},"description":"API key for authentication (query)"},{"name":"dataset_id","in":"query","required":true,"schema":{"type":"string","title":"Dataset Id"}},{"name":"start_time","in":"query","required":false,"schema":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"description":"Filter to rows where time index >= start_time (ISO 8601)","title":"Start Time"},"description":"Filter to rows where time index >= start_time (ISO 8601)"},{"name":"end_time","in":"query","required":false,"schema":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"description":"Filter to rows where time index < end_time (ISO 8601 timestamp)","title":"End Time"},"description":"Filter to rows where time index < end_time (ISO 8601 timestamp)"},{"name":"price_threshold","in":"query","required":false,"schema":{"anyOf":[{"type":"number"},{"type":"null"}],"description":"Optional threshold. When set, only include rows where ABS(configured shadow price column) > price_threshold.","title":"Price Threshold"},"description":"Optional threshold. When set, only include rows where ABS(configured shadow price column) > price_threshold."},{"name":"x-api-key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"API key for authentication (header)","title":"X-Api-Key"},"description":"API key for authentication (header)"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/BindingConstraintCountResponse"},"title":"Response List Constraint Binding Counts By Period V1 Constraints Binding Counts Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}}},"components":{"schemas":{"BindingConstraintCountResponse":{"properties":{"period_start_utc":{"type":"string","format":"date-time","title":"Period Start Utc"},"binding_constraint_count":{"type":"integer","title":"Binding Constraint Count"},"binding_constraint_ids":{"items":{"type":"string"},"type":"array","title":"Binding Constraint Ids"}},"type":"object","required":["period_start_utc","binding_constraint_count","binding_constraint_ids"],"title":"BindingConstraintCountResponse","description":"Count of unique binding constraints for a single UTC aggregation period."},"HTTPValidationError":{"properties":{"detail":{"items":{"$ref":"#/components/schemas/ValidationError"},"type":"array","title":"Detail"}},"type":"object","title":"HTTPValidationError"},"ValidationError":{"properties":{"loc":{"items":{"anyOf":[{"type":"string"},{"type":"integer"}]},"type":"array","title":"Location"},"msg":{"type":"string","title":"Message"},"type":{"type":"string","title":"Error Type"}},"type":"object","required":["loc","msg","type"],"title":"ValidationError"}}}}
```

## List Constraint Binding Absolute Costs By Period

> Summarize absolute binding cost per UTC period for a dataset.

```json
{"openapi":"3.1.0","info":{"title":"Grid Status API","version":"1.3.0"},"servers":[{"url":"https://api.gridstatus.io/v1"}],"paths":{"/constraints/binding/absolute-costs":{"get":{"tags":["Constraints"],"summary":"List Constraint Binding Absolute Costs By Period","description":"Summarize absolute binding cost per UTC period for a dataset.","operationId":"list_constraint_binding_absolute_costs_by_period_v1_constraints_binding_absolute_costs_get","parameters":[{"name":"aggregation_period","in":"query","required":false,"schema":{"enum":["hour","day","month","year"],"type":"string","description":"UTC aggregation period for grouping absolute costs. Supported values: hour, day, month, year.","default":"hour","title":"Aggregation Period"},"description":"UTC aggregation period for grouping absolute costs. Supported values: hour, day, month, year."},{"name":"api_key","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"API key for authentication (query)","title":"Api Key"},"description":"API key for authentication (query)"},{"name":"dataset_id","in":"query","required":true,"schema":{"type":"string","title":"Dataset Id"}},{"name":"start_time","in":"query","required":false,"schema":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"description":"Filter to rows where time index >= start_time (ISO 8601)","title":"Start Time"},"description":"Filter to rows where time index >= start_time (ISO 8601)"},{"name":"end_time","in":"query","required":false,"schema":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"description":"Filter to rows where time index < end_time (ISO 8601 timestamp)","title":"End Time"},"description":"Filter to rows where time index < end_time (ISO 8601 timestamp)"},{"name":"price_threshold","in":"query","required":false,"schema":{"anyOf":[{"type":"number"},{"type":"null"}],"description":"Optional threshold. When set, only include rows where ABS(configured shadow price column) > price_threshold.","title":"Price Threshold"},"description":"Optional threshold. When set, only include rows where ABS(configured shadow price column) > price_threshold."},{"name":"x-api-key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"API key for authentication (header)","title":"X-Api-Key"},"description":"API key for authentication (header)"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/BindingConstraintAbsoluteCostResponse"},"title":"Response List Constraint Binding Absolute Costs By Period V1 Constraints Binding Absolute Costs Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}}},"components":{"schemas":{"BindingConstraintAbsoluteCostResponse":{"properties":{"period_start_utc":{"type":"string","format":"date-time","title":"Period Start Utc"},"absolute_cost":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Absolute Cost"}},"type":"object","required":["period_start_utc","absolute_cost"],"title":"BindingConstraintAbsoluteCostResponse","description":"Absolute binding cost for a single UTC aggregation period."},"HTTPValidationError":{"properties":{"detail":{"items":{"$ref":"#/components/schemas/ValidationError"},"type":"array","title":"Detail"}},"type":"object","title":"HTTPValidationError"},"ValidationError":{"properties":{"loc":{"items":{"anyOf":[{"type":"string"},{"type":"integer"}]},"type":"array","title":"Location"},"msg":{"type":"string","title":"Message"},"type":{"type":"string","title":"Error Type"}},"type":"object","required":["loc","msg","type"],"title":"ValidationError"}}}}
```

## Get Constraint Binding Heat Map

> Return absolute costs and shadow-price aggregates by bucket and constraint.

```json
{"openapi":"3.1.0","info":{"title":"Grid Status API","version":"1.3.0"},"servers":[{"url":"https://api.gridstatus.io/v1"}],"paths":{"/constraints/binding/heat_map":{"get":{"tags":["Constraints"],"summary":"Get Constraint Binding Heat Map","description":"Return absolute costs and shadow-price aggregates by bucket and constraint.","operationId":"get_constraint_binding_heat_map_v1_constraints_binding_heat_map_get","parameters":[{"name":"api_key","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"API key for authentication (query)","title":"Api Key"},"description":"API key for authentication (query)"},{"name":"dataset_id","in":"query","required":true,"schema":{"type":"string","title":"Dataset Id"}},{"name":"start_time","in":"query","required":true,"schema":{"type":"string","format":"date-time","description":"Filter to rows where time index >= start_time (ISO 8601)","title":"Start Time"},"description":"Filter to rows where time index >= start_time (ISO 8601)"},{"name":"end_time","in":"query","required":true,"schema":{"type":"string","format":"date-time","description":"Filter to rows where time index < end_time (ISO 8601 timestamp)","title":"End Time"},"description":"Filter to rows where time index < end_time (ISO 8601 timestamp)"},{"name":"timezone","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Optional IANA timezone used for daily bucket boundaries. Defaults to the dataset market timezone.","title":"Timezone"},"description":"Optional IANA timezone used for daily bucket boundaries. Defaults to the dataset market timezone."},{"name":"bucket_mode","in":"query","required":false,"schema":{"enum":["auto","raw","hourly","daily"],"type":"string","description":"Bucket resolution. Raw preserves the native interval; hourly and daily use explicit buckets. Auto derives resolution from the native interval and selected range. Explicit modes that exceed the range limit resolve to the nearest available mode.","default":"auto","title":"Bucket Mode"},"description":"Bucket resolution. Raw preserves the native interval; hourly and daily use explicit buckets. Auto derives resolution from the native interval and selected range. Explicit modes that exceed the range limit resolve to the nearest available mode."},{"name":"group_by","in":"query","required":false,"schema":{"enum":["constraint","constraint_contingency"],"type":"string","description":"Group rows by constraint and contingency by default, or by constraint only.","default":"constraint_contingency","title":"Group By"},"description":"Group rows by constraint and contingency by default, or by constraint only."},{"name":"days_of_week","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Optional comma-separated market-local days of the week, where Monday is 1 and Sunday is 7. An empty value matches no rows.","title":"Days Of Week"},"description":"Optional comma-separated market-local days of the week, where Monday is 1 and Sunday is 7. An empty value matches no rows."},{"name":"hours","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Optional comma-separated market-local hour starts from 0 through 23. An empty value matches no rows.","title":"Hours"},"description":"Optional comma-separated market-local hour starts from 0 through 23. An empty value matches no rows."},{"name":"x-api-key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"API key for authentication (header)","title":"X-Api-Key"},"description":"API key for authentication (header)"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"anyOf":[{"$ref":"#/components/schemas/ConstraintBindingHeatMapSupportedResponse"},{"$ref":"#/components/schemas/ConstraintBindingHeatMapUnsupportedResponse"}],"title":"Response Get Constraint Binding Heat Map V1 Constraints Binding Heat Map Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}}},"components":{"schemas":{"ConstraintBindingHeatMapSupportedResponse":{"properties":{"timezone":{"type":"string","title":"Timezone"},"group_by":{"type":"string","enum":["constraint","constraint_contingency"],"title":"Group By"},"supports_contingency_grouping":{"type":"boolean","title":"Supports Contingency Grouping"},"constraint_names":{"additionalProperties":{"type":"string"},"type":"object","title":"Constraint Names"},"contingency_names":{"additionalProperties":{"type":"string"},"type":"object","title":"Contingency Names"},"native_interval_minutes":{"type":"integer","title":"Native Interval Minutes"},"interval_minutes":{"type":"integer","title":"Interval Minutes"},"bucket_mode":{"type":"string","enum":["raw","hourly","daily"],"title":"Bucket Mode"},"available_bucket_modes":{"items":{"type":"string","enum":["raw","hourly","daily"]},"type":"array","title":"Available Bucket Modes","description":"Bucket modes available for the native interval and range."},"cells":{"items":{"$ref":"#/components/schemas/ConstraintBindingHeatMapCellResponse"},"type":"array","title":"Cells"},"row_summaries":{"items":{"$ref":"#/components/schemas/ConstraintBindingHeatMapRowSummaryResponse"},"type":"array","title":"Row Summaries"},"unsupported_reason":{"type":"null","title":"Unsupported Reason"}},"type":"object","required":["timezone","group_by","supports_contingency_grouping","native_interval_minutes","interval_minutes","bucket_mode","available_bucket_modes"],"title":"ConstraintBindingHeatMapSupportedResponse","description":"Absolute binding cost and shadow-price aggregates for a supported dataset."},"ConstraintBindingHeatMapCellResponse":{"properties":{"absolute_cost":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Absolute Cost","description":"Total absolute cost: the sum of duration-weighted absolute shadow prices, or null when any binding row has an unknown absolute cost."},"peak_shadow_price":{"type":"number","title":"Peak Shadow Price","description":"Signed shadow price with the greatest absolute value."},"mean_shadow_price":{"type":"number","title":"Mean Shadow Price","description":"Mean shadow price."},"binding_interval_count":{"type":"integer","title":"Binding Interval Count","description":"Number of underlying binding rows."},"bucket_start_utc":{"type":"string","format":"date-time","title":"Bucket Start Utc"},"interval_start_utc":{"type":"string","format":"date-time","title":"Interval Start Utc","description":"UTC timestamp of the shadow price with the greatest absolute value in the bucket. It may be an irregular dataset time index."},"constraint_gs_entity_id":{"type":"string","title":"Constraint Gs Entity Id"},"contingency_gs_entity_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Contingency Gs Entity Id"}},"type":"object","required":["absolute_cost","peak_shadow_price","mean_shadow_price","binding_interval_count","bucket_start_utc","interval_start_utc","constraint_gs_entity_id"],"title":"ConstraintBindingHeatMapCellResponse"},"ConstraintBindingHeatMapRowSummaryResponse":{"properties":{"constraint_gs_entity_id":{"type":"string","title":"Constraint Gs Entity Id"},"contingency_gs_entity_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Contingency Gs Entity Id"},"metrics":{"$ref":"#/components/schemas/ConstraintBindingHeatMapMetrics"}},"type":"object","required":["constraint_gs_entity_id","metrics"],"title":"ConstraintBindingHeatMapRowSummaryResponse"},"ConstraintBindingHeatMapMetrics":{"properties":{"absolute_cost":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Absolute Cost","description":"Total absolute cost: the sum of duration-weighted absolute shadow prices, or null when any binding row has an unknown absolute cost."},"peak_shadow_price":{"type":"number","title":"Peak Shadow Price","description":"Signed shadow price with the greatest absolute value."},"mean_shadow_price":{"type":"number","title":"Mean Shadow Price","description":"Mean shadow price."},"binding_interval_count":{"type":"integer","title":"Binding Interval Count","description":"Number of underlying binding rows."}},"type":"object","required":["absolute_cost","peak_shadow_price","mean_shadow_price","binding_interval_count"],"title":"ConstraintBindingHeatMapMetrics"},"ConstraintBindingHeatMapUnsupportedResponse":{"properties":{"timezone":{"type":"string","title":"Timezone"},"group_by":{"type":"string","enum":["constraint","constraint_contingency"],"title":"Group By"},"supports_contingency_grouping":{"type":"boolean","title":"Supports Contingency Grouping"},"constraint_names":{"additionalProperties":{"type":"string"},"type":"object","title":"Constraint Names"},"contingency_names":{"additionalProperties":{"type":"string"},"type":"object","title":"Contingency Names"},"native_interval_minutes":{"type":"null","title":"Native Interval Minutes"},"interval_minutes":{"type":"null","title":"Interval Minutes"},"bucket_mode":{"type":"null","title":"Bucket Mode"},"available_bucket_modes":{"items":{"type":"string","enum":["raw","hourly","daily"]},"type":"array","maxItems":0,"title":"Available Bucket Modes"},"cells":{"items":{"$ref":"#/components/schemas/ConstraintBindingHeatMapCellResponse"},"type":"array","maxItems":0,"title":"Cells"},"row_summaries":{"items":{"$ref":"#/components/schemas/ConstraintBindingHeatMapRowSummaryResponse"},"type":"array","maxItems":0,"title":"Row Summaries"},"unsupported_reason":{"type":"string","title":"Unsupported Reason"}},"type":"object","required":["timezone","group_by","supports_contingency_grouping","unsupported_reason"],"title":"ConstraintBindingHeatMapUnsupportedResponse","description":"Binding heat map metadata for a dataset that cannot be displayed."},"HTTPValidationError":{"properties":{"detail":{"items":{"$ref":"#/components/schemas/ValidationError"},"type":"array","title":"Detail"}},"type":"object","title":"HTTPValidationError"},"ValidationError":{"properties":{"loc":{"items":{"anyOf":[{"type":"string"},{"type":"integer"}]},"type":"array","title":"Location"},"msg":{"type":"string","title":"Message"},"type":{"type":"string","title":"Error Type"}},"type":"object","required":["loc","msg","type"],"title":"ValidationError"}}}}
```

## Get Constraint

> Get data for a specific constraint by its GS entity ID.

```json
{"openapi":"3.1.0","info":{"title":"Grid Status API","version":"1.3.0"},"servers":[{"url":"https://api.gridstatus.io/v1"}],"paths":{"/constraints/{gs_entity_id}":{"get":{"tags":["Constraints"],"summary":"Get Constraint","description":"Get data for a specific constraint by its GS entity ID.","operationId":"get_constraint_v1_constraints__gs_entity_id__get","parameters":[{"name":"gs_entity_id","in":"path","required":true,"schema":{"type":"string","title":"GS Entity ID","description":"GS entity ID of the constraint to query"},"description":"GS entity ID of the constraint to query"},{"name":"api_key","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"API key for authentication (query)","title":"Api Key"},"description":"API key for authentication (query)"},{"name":"x-api-key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"API key for authentication (header)","title":"X-Api-Key"},"description":"API key for authentication (header)"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ConstraintResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}}},"components":{"schemas":{"ConstraintResponse":{"properties":{"gs_entity_id":{"type":"string","title":"Gs Entity Id"},"constraint_name":{"type":"string","title":"Constraint Name"},"market_id":{"type":"string","title":"Market Id"},"earliest_seen_utc":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Earliest Seen Utc"},"latest_seen_utc":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Latest Seen Utc"},"available_datasets":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"null"}],"title":"Available Datasets"},"rt_absolute_cost":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Rt Absolute Cost"},"da_absolute_cost":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Da Absolute Cost"},"gs_created_at_utc":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Gs Created At Utc"},"gs_updated_at_utc":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Gs Updated At Utc"}},"type":"object","required":["gs_entity_id","constraint_name","market_id","earliest_seen_utc","latest_seen_utc","available_datasets"],"title":"ConstraintResponse"},"HTTPValidationError":{"properties":{"detail":{"items":{"$ref":"#/components/schemas/ValidationError"},"type":"array","title":"Detail"}},"type":"object","title":"HTTPValidationError"},"ValidationError":{"properties":{"loc":{"items":{"anyOf":[{"type":"string"},{"type":"integer"}]},"type":"array","title":"Location"},"msg":{"type":"string","title":"Message"},"type":{"type":"string","title":"Error Type"}},"type":"object","required":["loc","msg","type"],"title":"ValidationError"}}}}
```

## Get Constraint Intervals

> Year/month/day-level statistics on binding intervals in ISO local time.

```json
{"openapi":"3.1.0","info":{"title":"Grid Status API","version":"1.3.0"},"servers":[{"url":"https://api.gridstatus.io/v1"}],"paths":{"/constraints/{constraint_id}/intervals":{"get":{"tags":["Constraints"],"summary":"Get Constraint Intervals","description":"Year/month/day-level statistics on binding intervals in ISO local time.","operationId":"get_constraint_intervals_v1_constraints__constraint_id__intervals_get","parameters":[{"name":"constraint_id","in":"path","required":true,"schema":{"type":"string","title":"Constraint ID","description":"GS entity ID of the constraint to query"},"description":"GS entity ID of the constraint to query"},{"name":"dataset_id","in":"query","required":true,"schema":{"type":"string","title":"Dataset Id"}},{"name":"contingency_id","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Contingency ID","description":"Optional contingency GS entity ID filter. Applied only when the dataset contains contingency_gs_entity_id."},"description":"Optional contingency GS entity ID filter. Applied only when the dataset contains contingency_gs_entity_id."},{"name":"api_key","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"API key for authentication (query)","title":"Api Key"},"description":"API key for authentication (query)"},{"name":"x-api-key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"API key for authentication (header)","title":"X-Api-Key"},"description":"API key for authentication (header)"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/ConstraintIntervalResponse"},"title":"Response Get Constraint Intervals V1 Constraints  Constraint Id  Intervals Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}}},"components":{"schemas":{"ConstraintIntervalResponse":{"properties":{"year":{"type":"integer","title":"Year"},"count":{"type":"integer","title":"Count"},"months":{"anyOf":[{"items":{"$ref":"#/components/schemas/ConstraintIntervalMonthResponse"},"type":"array"},{"type":"null"}],"title":"Months"}},"type":"object","required":["year","count"],"title":"ConstraintIntervalResponse","description":"Year/month/day-level statistics for constraint binding intervals.\n\nYear: months with data and count in each.\nMonth: days with data and count in each.\nDay: times (HH:MM:SS strings) for unique timestamps on that day."},"ConstraintIntervalMonthResponse":{"properties":{"month":{"type":"integer","title":"Month"},"count":{"type":"integer","title":"Count"},"days":{"anyOf":[{"items":{"$ref":"#/components/schemas/ConstraintIntervalDayResponse"},"type":"array"},{"type":"null"}],"title":"Days"}},"type":"object","required":["month","count"],"title":"ConstraintIntervalMonthResponse","description":"Month-level count of unique timestamps within a year."},"ConstraintIntervalDayResponse":{"properties":{"day":{"type":"integer","title":"Day"},"count":{"type":"integer","title":"Count"},"times":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"null"}],"title":"Times"}},"type":"object","required":["day","count"],"title":"ConstraintIntervalDayResponse","description":"Day-level count of unique timestamps within a month."},"HTTPValidationError":{"properties":{"detail":{"items":{"$ref":"#/components/schemas/ValidationError"},"type":"array","title":"Detail"}},"type":"object","title":"HTTPValidationError"},"ValidationError":{"properties":{"loc":{"items":{"anyOf":[{"type":"string"},{"type":"integer"}]},"type":"array","title":"Location"},"msg":{"type":"string","title":"Message"},"type":{"type":"string","title":"Error Type"}},"type":"object","required":["loc","msg","type"],"title":"ValidationError"}}}}
```

## List Contingencies For Constraint

> Contingencies binding for a constraint in a dataset/time window.

```json
{"openapi":"3.1.0","info":{"title":"Grid Status API","version":"1.3.0"},"servers":[{"url":"https://api.gridstatus.io/v1"}],"paths":{"/constraints/{constraint_id}/contingencies":{"get":{"tags":["Constraints"],"summary":"List Contingencies For Constraint","description":"Contingencies binding for a constraint in a dataset/time window.","operationId":"list_contingencies_for_constraint_v1_constraints__constraint_id__contingencies_get","parameters":[{"name":"constraint_id","in":"path","required":true,"schema":{"type":"string","title":"Constraint ID","description":"Constraint GS entity ID to filter by (constraint_gs_entity_id)"},"description":"Constraint GS entity ID to filter by (constraint_gs_entity_id)"},{"name":"dataset_id","in":"query","required":true,"schema":{"type":"string","title":"Dataset Id"}},{"name":"include_binding_stats","in":"query","required":false,"schema":{"type":"boolean","description":"When true, include binding_intervals and absolute_cost and apply start_time/end_time/time filters. Default returns id and name only.","default":false,"title":"Include Binding Stats"},"description":"When true, include binding_intervals and absolute_cost and apply start_time/end_time/time filters. Default returns id and name only."},{"name":"start_time","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Start time (ISO timestamp) for filtering (inclusive). Requires time index column. Only used when include_binding_stats is true.","title":"Start Time"},"description":"Start time (ISO timestamp) for filtering (inclusive). Requires time index column. Only used when include_binding_stats is true."},{"name":"end_time","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"End time (ISO timestamp) for filtering (exclusive). Requires time index column. Only used when include_binding_stats is true.","title":"End Time"},"description":"End time (ISO timestamp) for filtering (exclusive). Requires time index column. Only used when include_binding_stats is true."},{"name":"time","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Optional specific timestamp to filter results. Cannot be used with start_time or end_time. Only used when include_binding_stats is true.","title":"Time"},"description":"Optional specific timestamp to filter results. Cannot be used with start_time or end_time. Only used when include_binding_stats is true."},{"name":"api_key","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"API key for authentication (query)","title":"Api Key"},"description":"API key for authentication (query)"},{"name":"x-api-key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"API key for authentication (header)","title":"X-Api-Key"},"description":"API key for authentication (header)"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/ContingencyResponse"},"title":"Response List Contingencies For Constraint V1 Constraints  Constraint Id  Contingencies Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}}},"components":{"schemas":{"ContingencyResponse":{"properties":{"id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Id"},"name":{"type":"string","title":"Name"},"binding_intervals":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Binding Intervals"},"absolute_cost":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Absolute Cost"}},"type":"object","required":["id","name"],"title":"ContingencyResponse","description":"Contingency with id, name, and optional binding stats."},"HTTPValidationError":{"properties":{"detail":{"items":{"$ref":"#/components/schemas/ValidationError"},"type":"array","title":"Detail"}},"type":"object","title":"HTTPValidationError"},"ValidationError":{"properties":{"loc":{"items":{"anyOf":[{"type":"string"},{"type":"integer"}]},"type":"array","title":"Location"},"msg":{"type":"string","title":"Message"},"type":{"type":"string","title":"Error Type"}},"type":"object","required":["loc","msg","type"],"title":"ValidationError"}}}}
```


# Outages

## List Active Outages

> List scheduled transmission outages that overlap a time window.\
> \
> Latest plan per \`\`(ticket, facility\_name, item)\`\` with\
> \`\`timestamp\_utc < end\_time\`\`. Keep rows whose planned interval overlaps\
> \`\`\[start\_time, end\_time)\`\`. Optional \`\`start\_date\`\` keeps only plans whose\
> planned start is on or after that instant. Does not filter on Status, Daily\
> recurrence, or \`\`open\_closed\`\`. Station lat/lon are joined in the same query.\
> When more rows match than \`\`limit\`\`, \`\`truncated\`\` is true.

```json
{"openapi":"3.1.0","info":{"title":"Grid Status API","version":"1.3.0"},"servers":[{"url":"https://api.gridstatus.io/v1"}],"paths":{"/outages/{market_id}/active":{"get":{"tags":["Outages"],"summary":"List Active Outages","description":"List scheduled transmission outages that overlap a time window.\n\nLatest plan per ``(ticket, facility_name, item)`` with\n``timestamp_utc < end_time``. Keep rows whose planned interval overlaps\n``[start_time, end_time)``. Optional ``start_date`` keeps only plans whose\nplanned start is on or after that instant. Does not filter on Status, Daily\nrecurrence, or ``open_closed``. Station lat/lon are joined in the same query.\nWhen more rows match than ``limit``, ``truncated`` is true.","operationId":"list_active_outages_v1_outages__market_id__active_get","parameters":[{"name":"market_id","in":"path","required":true,"schema":{"type":"string","description":"Market id (e.g. pjm). Determines outage + coordinates datasets.","title":"Market Id"},"description":"Market id (e.g. pjm). Determines outage + coordinates datasets."},{"name":"start_time","in":"query","required":true,"schema":{"type":"string","format":"date-time","description":"Inclusive start of a half-open window (ISO 8601). Use with end_time. Rows whose planned interval overlaps [start_time, end_time) are returned.","title":"Start Time"},"description":"Inclusive start of a half-open window (ISO 8601). Use with end_time. Rows whose planned interval overlaps [start_time, end_time) are returned."},{"name":"end_time","in":"query","required":true,"schema":{"type":"string","format":"date-time","description":"Exclusive end of a half-open window (ISO 8601). Also the date-log as-of cutoff (timestamp_utc < end_time).","title":"End Time"},"description":"Exclusive end of a half-open window (ISO 8601). Also the date-log as-of cutoff (timestamp_utc < end_time)."},{"name":"start_date","in":"query","required":false,"schema":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"description":"Optional inclusive lower bound on planned interval_start_utc (ISO 8601). When omitted, outages that started at any time are included.","title":"Start Date"},"description":"Optional inclusive lower bound on planned interval_start_utc (ISO 8601). When omitted, outages that started at any time are included."},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":100000,"minimum":1,"description":"Maximum number of active outage equipment rows to return. When more rows match, truncated is true and rows is trimmed to this limit.","default":50000,"title":"Limit"},"description":"Maximum number of active outage equipment rows to return. When more rows match, truncated is true and rows is trimmed to this limit."},{"name":"api_key","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"API key for authentication (query)","title":"Api Key"},"description":"API key for authentication (query)"},{"name":"x-api-key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"API key for authentication (header)","title":"X-Api-Key"},"description":"API key for authentication (header)"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PJMActiveOutagesResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}}},"components":{"schemas":{"PJMActiveOutagesResponse":{"properties":{"as_of_utc":{"type":"string","format":"date-time","title":"As Of Utc"},"start_time":{"type":"string","format":"date-time","title":"Start Time"},"end_time":{"type":"string","format":"date-time","title":"End Time"},"publish_time_utc":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Publish Time Utc"},"truncated":{"type":"boolean","title":"Truncated"},"rows":{"items":{"$ref":"#/components/schemas/PJMActiveOutageRow"},"type":"array","title":"Rows"}},"type":"object","required":["as_of_utc","start_time","end_time","truncated","rows"],"title":"PJMActiveOutagesResponse","description":"Outages whose planned window overlaps ``[start_time, end_time)``.\n\n``as_of_utc`` is the date-log cutoff (``timestamp_utc < as_of_utc``) and\nequals ``end_time``. ``truncated`` is true when more matching rows exist\nthan ``limit``; ``rows`` is then trimmed to ``limit``."},"PJMActiveOutageRow":{"properties":{"item":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Item"},"ticket":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Ticket"},"zone":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Zone"},"facility_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Facility Name"},"equipment_type":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Equipment Type"},"station_1":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Station 1"},"station_2":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Station 2"},"from_substation":{"anyOf":[{"$ref":"#/components/schemas/SubstationLocation"},{"type":"null"}]},"to_substation":{"anyOf":[{"$ref":"#/components/schemas/SubstationLocation"},{"type":"null"}]},"voltage":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Voltage"},"equipment_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Equipment Name"},"open_closed":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Open Closed"},"outage_type":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Outage Type"},"cause":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Cause"},"status":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Status"},"interval_start_utc":{"type":"string","format":"date-time","title":"Interval Start Utc"},"interval_end_utc":{"type":"string","format":"date-time","title":"Interval End Utc"},"publish_time_utc":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Publish Time Utc"},"timestamp_utc":{"type":"string","format":"date-time","title":"Timestamp Utc"}},"type":"object","required":["interval_start_utc","interval_end_utc","timestamp_utc"],"title":"PJMActiveOutageRow","description":"One equipment row from PJM's scheduled transmission-outages date log.\n\n``station_1`` / ``station_2`` prefer the facility-geometry names (historical\nISO rows often leave ``station_2`` empty). Mapped coordinates and display\nnames come from the same view as ``from_substation`` / ``to_substation``\n(null when that end has no coords)."},"SubstationLocation":{"properties":{"latitude":{"type":"number","title":"Latitude"},"longitude":{"type":"number","title":"Longitude"},"name":{"type":"string","title":"Name"}},"type":"object","required":["latitude","longitude","name"],"title":"SubstationLocation","description":"Lat/lon and display name for a substation."},"HTTPValidationError":{"properties":{"detail":{"items":{"$ref":"#/components/schemas/ValidationError"},"type":"array","title":"Detail"}},"type":"object","title":"HTTPValidationError"},"ValidationError":{"properties":{"loc":{"items":{"anyOf":[{"type":"string"},{"type":"integer"}]},"type":"array","title":"Location"},"msg":{"type":"string","title":"Message"},"type":{"type":"string","title":"Error Type"}},"type":"object","required":["loc","msg","type"],"title":"ValidationError"}}}}
```


# Pricing Locations

## List Pricing Locations

> Get a list of pricing locations with optional filtering by ISOs, zones,\
> zone types and a search term.\
> \
> Args:\
> &#x20;   params: Query parameters for filtering pricing locations\
> &#x20;   sort\_column: Column to sort by.\
> &#x20;   sort\_order: Sort order - 'asc' or 'desc'.

```json
{"openapi":"3.1.0","info":{"title":"Grid Status API","version":"1.3.0"},"servers":[{"url":"https://api.gridstatus.io/v1"}],"paths":{"/pricing_locations":{"get":{"tags":["Pricing Locations"],"summary":"List Pricing Locations","description":"Get a list of pricing locations with optional filtering by ISOs, zones,\nzone types and a search term.\n\nArgs:\n    params: Query parameters for filtering pricing locations\n    sort_column: Column to sort by.\n    sort_order: Sort order - 'asc' or 'desc'.","operationId":"list_pricing_locations_v1_pricing_locations_get","parameters":[{"name":"sort_column","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Sort Column"}},{"name":"sort_order","in":"query","required":false,"schema":{"anyOf":[{"$ref":"#/components/schemas/OrderBy"},{"type":"null"}],"title":"Sort Order"}},{"name":"api_key","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"API key for authentication (query)","title":"Api Key"},"description":"API key for authentication (query)"},{"name":"search","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Optional search term to filter locations by name","title":"Search"},"description":"Optional search term to filter locations by name"},{"name":"isos","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Comma-separated list of market IDs to filter by","title":"Isos"},"description":"Comma-separated list of market IDs to filter by"},{"name":"zones","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Comma-separated list of zones to filter by","title":"Zones"},"description":"Comma-separated list of zones to filter by"},{"name":"status","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Comma-separated list of statuses to filter by","title":"Status"},"description":"Comma-separated list of statuses to filter by"},{"name":"location_types","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Comma-separated list of location types to filter by","title":"Location Types"},"description":"Comma-separated list of location types to filter by"},{"name":"has_geo_data","in":"query","required":false,"schema":{"anyOf":[{"type":"boolean"},{"type":"null"}],"description":"Filter by whether locations have geographic data","title":"Has Geo Data"},"description":"Filter by whether locations have geographic data"},{"name":"x-api-key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"API key for authentication (header)","title":"X-Api-Key"},"description":"API key for authentication (header)"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FacetedSearchResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}}},"components":{"schemas":{"OrderBy":{"type":"string","enum":["asc","desc"],"title":"OrderBy"},"FacetedSearchResponse":{"properties":{"items":{"items":{"additionalProperties":true,"type":"object"},"type":"array","title":"Items"},"total_items":{"type":"integer","title":"Total Items"},"facets":{"additionalProperties":{"items":{"additionalProperties":true,"type":"object"},"type":"array"},"type":"object","title":"Facets"}},"type":"object","required":["items","total_items","facets"],"title":"FacetedSearchResponse","description":"Response from get_items_and_facets containing items, total count, and facets."},"HTTPValidationError":{"properties":{"detail":{"items":{"$ref":"#/components/schemas/ValidationError"},"type":"array","title":"Detail"}},"type":"object","title":"HTTPValidationError"},"ValidationError":{"properties":{"loc":{"items":{"anyOf":[{"type":"string"},{"type":"integer"}]},"type":"array","title":"Location"},"msg":{"type":"string","title":"Message"},"type":{"type":"string","title":"Error Type"}},"type":"object","required":["loc","msg","type"],"title":"ValidationError"}}}}
```

## List Nearby Pricing Locations

> Get a list of pricing locations near the provided latitude/longitude\
> or gs\_entity\_id. User must provide either latitude and longitude or a\
> gs\_entity\_id, but not both.

```json
{"openapi":"3.1.0","info":{"title":"Grid Status API","version":"1.3.0"},"servers":[{"url":"https://api.gridstatus.io/v1"}],"paths":{"/pricing_locations/nearby":{"get":{"tags":["Pricing Locations"],"summary":"List Nearby Pricing Locations","description":"Get a list of pricing locations near the provided latitude/longitude\nor gs_entity_id. User must provide either latitude and longitude or a\ngs_entity_id, but not both.","operationId":"list_nearby_pricing_locations_v1_pricing_locations_nearby_get","parameters":[{"name":"api_key","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"API key for authentication (query)","title":"Api Key"},"description":"API key for authentication (query)"},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":100,"minimum":1,"default":20,"title":"Limit"}},{"name":"latitude","in":"query","required":false,"schema":{"anyOf":[{"type":"number","maximum":90,"minimum":-90},{"type":"null"}],"description":"The latitude of the location to search","title":"Latitude"},"description":"The latitude of the location to search"},{"name":"longitude","in":"query","required":false,"schema":{"anyOf":[{"type":"number","maximum":180,"minimum":-180},{"type":"null"}],"description":"The longitude of the location to search","title":"Longitude"},"description":"The longitude of the location to search"},{"name":"gs_entity_id","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"The GS entity ID of the location to search","title":"Gs Entity Id"},"description":"The GS entity ID of the location to search"},{"name":"x-api-key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"API key for authentication (header)","title":"X-Api-Key"},"description":"API key for authentication (header)"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/NearbyPricingLocationItem"},"title":"Response List Nearby Pricing Locations V1 Pricing Locations Nearby Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}}},"components":{"schemas":{"NearbyPricingLocationItem":{"properties":{"gs_entity_id":{"type":"string","title":"Gs Entity Id"},"location":{"type":"string","title":"Location"},"market_id":{"type":"string","title":"Market Id"},"distance_in_miles":{"type":"number","title":"Distance In Miles"}},"type":"object","required":["gs_entity_id","location","market_id","distance_in_miles"],"title":"NearbyPricingLocationItem"},"HTTPValidationError":{"properties":{"detail":{"items":{"$ref":"#/components/schemas/ValidationError"},"type":"array","title":"Detail"}},"type":"object","title":"HTTPValidationError"},"ValidationError":{"properties":{"loc":{"items":{"anyOf":[{"type":"string"},{"type":"integer"}]},"type":"array","title":"Location"},"msg":{"type":"string","title":"Message"},"type":{"type":"string","title":"Error Type"}},"type":"object","required":["loc","msg","type"],"title":"ValidationError"}}}}
```

## Get Pricing Location

> Get data for a specific pricing location by its ID.

```json
{"openapi":"3.1.0","info":{"title":"Grid Status API","version":"1.3.0"},"servers":[{"url":"https://api.gridstatus.io/v1"}],"paths":{"/pricing_locations/{gs_entity_id}":{"get":{"tags":["Pricing Locations"],"summary":"Get Pricing Location","description":"Get data for a specific pricing location by its ID.","operationId":"get_pricing_location_v1_pricing_locations__gs_entity_id__get","parameters":[{"name":"gs_entity_id","in":"path","required":true,"schema":{"type":"string","title":"Pricing Location","description":"Name of the pricing location to query"},"description":"Name of the pricing location to query"},{"name":"api_key","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"API key for authentication (query)","title":"Api Key"},"description":"API key for authentication (query)"},{"name":"x-api-key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"API key for authentication (header)","title":"X-Api-Key"},"description":"API key for authentication (header)"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PricingLocationResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}}},"components":{"schemas":{"PricingLocationResponse":{"properties":{"gs_entity_id":{"type":"string","title":"Gs Entity Id"},"location":{"type":"string","title":"Location"},"location_type":{"type":"string","title":"Location Type"},"market_id":{"type":"string","title":"Market Id"},"baa":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Baa"},"zone":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Zone"},"zone_type":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Zone Type"},"latitude":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Latitude"},"longitude":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Longitude"},"pricing_datasets":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"null"}],"title":"Pricing Datasets"},"earliest_seen_utc":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Earliest Seen Utc"},"latest_seen_utc":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Latest Seen Utc"},"status_threshold_days":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Status Threshold Days"},"status":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Status"}},"type":"object","required":["gs_entity_id","location","location_type","market_id","baa","zone","zone_type","latitude","longitude","earliest_seen_utc","latest_seen_utc","status_threshold_days","status"],"title":"PricingLocationResponse"},"HTTPValidationError":{"properties":{"detail":{"items":{"$ref":"#/components/schemas/ValidationError"},"type":"array","title":"Detail"}},"type":"object","title":"HTTPValidationError"},"ValidationError":{"properties":{"loc":{"items":{"anyOf":[{"type":"string"},{"type":"integer"}]},"type":"array","title":"Location"},"msg":{"type":"string","title":"Message"},"type":{"type":"string","title":"Error Type"}},"type":"object","required":["loc","msg","type"],"title":"ValidationError"}}}}
```


# Getting Started

{% hint style="success" %}
Bulk CSV Downloads is a new offering. We welcome feedback as you get set up.
{% endhint %}

Bulk CSV Downloads provides our entire data catalog as compressed CSV flat files, delivered through AWS S3. The full export is approximately 1 TB compressed, and S3 gives you high-throughput parallel downloads to efficiently backfill your systems with our data.

We will share access to the export using AWS Security Token Service (STS), which grants you a temporary, limited-privilege credential to access the files in S3.

## Prerequisites

Please send us:

* AWS Account ID
* Confirmation you can use `sts:AssumeRole`

{% hint style="info" %}
You must use an IAM user or role when downloading files. A root account will not work (this is a limitation of AWS).
{% endhint %}

We will send you the following credentials so you can then access the data.

* `RoleArn`
* `ExternalId`

## Configure the AWS CLI (recommended option for downloading data)

First [install the AWS CLI](https://docs.aws.amazon.com/cli/latest/userguide/getting-started-install.html).

In `~/.aws/config`, add a `gridstatus` profile. Using a named profile will allow the CLI to handle credential refresh automatically.

```ini
[profile gridstatus]
role_arn = <RoleArn>
external_id = <ExternalId>
source_profile = default

s3 =
  max_concurrent_requests = 64
```

`max_concurrent_requests = 64` is a good starting point for bulk downloads — the AWS CLI default of 10 leaves throughput on the table.

Verify it works by listing the available datasets:

```bash
aws s3 ls s3://gs-catalog-csv/ --profile gridstatus
```

```
PRE aeso_daily_average_pool_price/
PRE aeso_fuel_mix/
PRE aeso_interchange/
...
```

If you see dataset folders listed, your credentials are working. See [Example Usage](/developers/bulk-csv-downloads/examples) for more commands.

## Transfer to Google Cloud Storage

If your destination is Google Cloud Storage, [Storage Transfer Service](https://cloud.google.com/storage-transfer/docs/source-amazon-s3) can sync `gs-catalog-csv` directly into a GCS bucket. It authenticates with [AWS IAM role for federated identity](https://docs.cloud.google.com/storage-transfer/docs/source-amazon-s3#federated_identity), so let us know you want to use this path and send us the **Subject ID** of your Google-managed service account. We'll add it to the role's trust policy, after which you can point a transfer job at `s3://gs-catalog-csv` using the `RoleArn` we provide you.

If federated identity isn't a fit, [`rclone`](https://rclone.org/s3/) supports `sts:AssumeRole` with `ExternalId` (`role_arn` + `role_external_id`) and can sync S3 → GCS from a Compute Engine VM using the credentials we already provide.

## Refresh schedule

The bucket is refreshed once per day around **06:00 UTC** by an incremental export, typically finishing within an hour. Any daily partition with rows that were inserted or updated upstream since the previous run is rewritten in full, so historical files can change on any given day when corrections or late-arriving data flow through. To avoid pulling files mid-rewrite, schedule large `aws s3 sync` jobs **outside the 06:00–07:00 UTC window**.

## Other Options

* **Python with** [**`s3fs`**](https://s3fs.readthedocs.io/) - Use `S3FileSystem` with `assume_role_arn` and `assume_role_kwargs` to download files.
* **Python with** [**`boto3`**](https://boto3.amazonaws.com/v1/documentation/api/latest/index.html) - Use `RefreshableCredentials` via STS `AssumeRole` to list and download objects with concurrent transfers.


# Folder Structure

{% hint style="warning" %}
Bulk CSV Downloads is in **early beta**. We'd love your feedback — please reach out with any questions or issues.
{% endhint %}

Data is organized in a four-level hierarchy: **dataset → year → month → daily files**. A per-dataset `manifest.json` sits at the root of each dataset folder.

```
s3://gs-catalog-csv/
├── aeso_daily_average_pool_price/
│   ├── aeso_daily_average_pool_price_manifest.json
│   ├── year=2000/
│   │   ├── month=01/
│   │   │   ├── 2000-01-01.csv.gz
│   │   │   ├── 2000-01-02.csv.gz
│   │   │   └── ...
│   │   ├── month=02/
│   │   └── ...
│   ├── year=2001/
│   └── ...
├── caiso_lmp_day_ahead_hourly/
│   ├── caiso_lmp_day_ahead_hourly_manifest.json
│   ├── year=2019/
│   └── ...
└── ... (hundreds of datasets)
```

* Each dataset is a top-level folder.
* `{dataset_id}_manifest.json` describes the dataset: column names and types, primary key, time columns, and an `export_watermark` block recording the last successful export. See [Manifest example](#manifest-example) below.
* Data is partitioned by `year=YYYY/month=MM/`.
* Individual files are gzipped CSVs named by date: `YYYY-MM-DD.csv.gz`.
  * For datasets with a `publish_time_column`, the date in the filename is the publish date of the data.
  * For datasets without a `publish_time_column`, the date in the filename is the `time_index_column` date of the data.
* File sizes vary widely by dataset. Across the catalog, gzipped CSVs average around 1 MB; the largest individual files (typically high-resolution LMP datasets) approach 200 MB, and the smallest (header-only or sparse days) are a few hundred bytes.
* The bucket is refreshed daily by an incremental export. Any daily partition containing rows that were inserted **or updated** upstream since the previous run is rewritten in full — corrections and late-arriving data flow through, not just newly published rows.

## Manifest example

Each dataset folder ships a `{dataset_id}_manifest.json` describing the schema and the most recent export. Real manifest from `aeso_daily_average_pool_price` (with the verbose per-day `runs` history elided for brevity):

```json
{
  "dataset_id": "aeso_daily_average_pool_price",
  "name": "AESO Daily Average Pool Price",
  "source": "aeso",
  "primary_key_columns": ["interval_start_utc"],
  "publish_time_column": null,
  "time_index_column": "interval_start_utc",
  "columns": [
    {"name": "interval_start_local", "type": "TIMESTAMP"},
    {"name": "interval_start_utc", "type": "TIMESTAMP"},
    {"name": "interval_end_local", "type": "TIMESTAMP"},
    {"name": "interval_end_utc", "type": "TIMESTAMP"},
    {"name": "daily_average", "type": "DOUBLE PRECISION"},
    {"name": "daily_on_peak_average", "type": "DOUBLE PRECISION"},
    {"name": "daily_off_peak_average", "type": "DOUBLE PRECISION"},
    {"name": "30_day_average", "type": "DOUBLE PRECISION"}
  ],
  "manifest_written_at": "2026-04-30T17:13:30.341687+00:00",
  "export_watermark": {
    "sync_cursor_at": "2026-04-30T17:13:11.942Z",
    "run_completed_at": "2026-04-30T17:13:30.341661+00:00",
    "rows_exported": 1
  },
  "runs": ["... (per-run export history elided)"]
}
```

Key fields:

* `columns` — full schema with name and type for every column in the CSV. Names are lower-case and match the CSV headers exactly.
* `primary_key_columns` — uniquely identify a row.
* `time_index_column` / `publish_time_column` — which column drives the per-file date partitioning.
* `export_watermark.sync_cursor_at` — every upstream change with a sync timestamp at or before this value is reflected in the exported files. Compare two days' manifests to detect what changed.
* `runs` — append-only log of every export run that wrote to the dataset. Each entry records the date list (succeeded and failed), the watermark window used, and the rollup totals.


# Example Usage

{% hint style="warning" %}
Bulk CSV Downloads is in **early beta**. We'd love your feedback — please reach out with any questions or issues.
{% endhint %}

All examples below use `--profile gridstatus` which assumes you have configured the named profile as described in [Getting Started](/developers/bulk-csv-downloads/getting-started).

## List available datasets

```bash
aws s3 ls s3://gs-catalog-csv/ --profile gridstatus
```

```
PRE aeso_daily_average_pool_price/
PRE aeso_fuel_mix/
PRE aeso_interchange/
PRE aeso_load/
PRE aeso_load_forecast/
PRE caiso_as_prices/
PRE caiso_curtailment/
PRE caiso_fuel_mix/
PRE caiso_lmp_day_ahead_hourly/
PRE caiso_lmp_real_time_5_min/
...
```

Each `PRE` entry is a dataset folder. There may be hundreds of datasets depending on your export.

## Explore available data range within a dataset

List the available years:

```bash
aws s3 ls s3://gs-catalog-csv/caiso_fuel_mix/ --profile gridstatus
```

```
PRE year=2018/
PRE year=2019/
PRE year=2020/
PRE year=2021/
PRE year=2022/
PRE year=2023/
PRE year=2024/
PRE year=2025/
PRE year=2026/
```

List months within a year:

```bash
aws s3 ls s3://gs-catalog-csv/caiso_fuel_mix/year=2025/ --profile gridstatus
```

```
PRE month=01/
PRE month=02/
PRE month=03/
...
PRE month=12/
```

List individual files within a month:

```bash
aws s3 ls s3://gs-catalog-csv/caiso_fuel_mix/year=2025/month=01/ --profile gridstatus
```

```
2026-02-18 21:26:05       9064 2025-01-01.csv.gz
2026-02-18 21:26:08       9235 2025-01-02.csv.gz
2026-02-18 21:26:07       9171 2025-01-03.csv.gz
...
2026-02-18 21:26:33       9442 2025-01-31.csv.gz
```

Get total file count and size for an entire dataset with `--recursive --summarize`:

```bash
aws s3 ls s3://gs-catalog-csv/pjm_lmp_real_time_5_min/ --recursive --summarize --profile gridstatus
```

```
...
2026-02-18 07:34:20  115232137 pjm_lmp_real_time_5_min/year=2026/month=02/2026-02-17.csv.gz

Total Objects: 2880
   Total Size: 228560459449
```

In this case, `pjm_lmp_real_time_5_min` contains 2,880 files totaling \~213 GB.

## Download data

Download a single file with `aws s3 cp`:

```bash
aws s3 cp s3://gs-catalog-csv/caiso_fuel_mix/year=2025/month=01/2025-01-01.csv.gz ./data/ --profile gridstatus
```

```
download: s3://gs-catalog-csv/caiso_fuel_mix/year=2025/month=01/2025-01-01.csv.gz to data/2025-01-01.csv.gz
```

Sync an entire dataset to a local folder:

```bash
aws s3 sync s3://gs-catalog-csv/ercot_spp_day_ahead_hourly/ ./data/ercot_spp_day_ahead_hourly/ --profile gridstatus
```

```
download: s3://...ercot_spp_day_ahead_hourly/year=2019/month=01/2019-01-01.csv.gz to data/ercot_spp_day_ahead_hourly/year=2019/month=01/2019-01-01.csv.gz
download: s3://...ercot_spp_day_ahead_hourly/year=2019/month=01/2019-01-02.csv.gz to data/ercot_spp_day_ahead_hourly/year=2019/month=01/2019-01-02.csv.gz
...
```

Sync a single year:

```bash
aws s3 sync s3://gs-catalog-csv/caiso_fuel_mix/year=2025/ ./data/caiso_fuel_mix/year=2025/ --profile gridstatus
```

Sync a single month:

```bash
aws s3 sync s3://gs-catalog-csv/caiso_fuel_mix/year=2025/month=01/ ./data/caiso_fuel_mix/year=2025/month=01/ --profile gridstatus
```

Use `--exclude` and `--include` to filter specific files within a year (e.g. only June 2025):

```bash
aws s3 sync s3://gs-catalog-csv/caiso_fuel_mix/year=2025/ ./data/caiso_fuel_mix/year=2025/ \
  --exclude "*" \
  --include "month=06/*" \
  --profile gridstatus
```

Sync everything at once:

```bash
aws s3 sync s3://gs-catalog-csv/ ./data/ --profile gridstatus
```

{% hint style="warning" %}
The full export is approximately **1 TB** (\~1 million files).
{% endhint %}

## Tips for bulk downloads

### Resumable syncs

`aws s3 sync` compares each remote object to its local counterpart by size and last-modified time, so re-running the same command after an interruption only re-downloads the missing or changed files. The same property makes it the right tool for incremental refreshes — point it at the same local directory each day and it will only pull what changed.

### Run outside the daily refresh window

The bucket is rewritten by an incremental export starting at **06:00 UTC** and typically finishing within an hour. Pulling during the refresh window can give you inconsistent state across datasets — some have been rewritten with the new partition, others haven't yet. For point-in-time consistency, schedule large jobs outside the 06:00–07:00 UTC window.

### Region matters

The bucket lives in `us-east-2` (Ohio). For the highest download throughput, run your client from EC2 in the same region.

### Reading the gzipped CSVs

Files are gzipped CSVs (`*.csv.gz`). Most modern data tools handle them natively without a manual `gunzip` step:

* **pandas:** `pd.read_csv("2025-01-01.csv.gz")` — auto-detected by extension.
* **polars:** `pl.read_csv("2025-01-01.csv.gz")` — auto-detected.
* **DuckDB:** `SELECT * FROM read_csv_auto('data/caiso_fuel_mix/year=2025/**/*.csv.gz')` — supports glob patterns, partition pruning via `hive_partitioning=true`, and reads gzip transparently.


# Getting Started

### Access our data in Snowflake Marketplace

**Why use Snowflake?**

* Robust Data Analytics: Run complex queries over a high volume of data.
* Seamless Data Integration: Query our data as if it were your own.
* Instant Access: Data available in near real-time with no ETL required.

### Free Trial

We offer a self-service free trial of our Snowflake Listing. You can access in via our public [Marketplace Listing here](https://app.snowflake.com/marketplace/listing/GZT1Z1IIJ3D/grid-status-power-market-data-north-america?search=grid+status).

### Paid Subscriptions

Paid subscriptions are delivered via Private Listings. After signing a contract with Grid Status, we’ll share a private listing tied to your Snowflake account.

### Finding Account Details

Visit your Snowflake account. Click on **"View account details"** as shown in the screenshot below, and send the listed *Data Sharing Account Identifier* to Grid Status.

<figure><img src="/files/vgyC2DaO9blCHKsG2Nss" alt=""><figcaption></figcaption></figure>

### How to Add a Private Listing

1. Once we share the listing, you’ll receive an email stating the data product is ready to be added to your account.
2. If you don’t receive the email, you can also manually add the dataset:
   * Log in to your Snowflake account
   * Go to **Data Products → Private Sharing**
   * Find and accept the listing

### What data is available on Snowflake?

Nearly all of our data is available on Snowflake within 1-2 minutes of being published via our API.

To check a specific dataset, look for "Available on Snowflake" in our [data catalog](https://www.gridstatus.io/datasets).

<figure><img src="/files/bZnHpvKikoR7RA8CVMxb" alt=""><figcaption></figcaption></figure>


# ERCOT Offer and Bid Curve Data

Throughout our Snowflake Marketplace Listing, offer and bid curve data is stored as arrays of (quantity, price) pairs. You will primarily see this in the ERCOT DAM and SCED 60 day disclourse dataset tables.

In this guide, we will walk you through how to query this data with some examples

### The raw offer curve data

This is what the raw data looks like. Compared to the ERCOT source data, the data on Grid Status is a single column that represents all offer curve points the QSE submitted

We organize the data this way because there could be a variable number of points on the bid/offer curve. By organizing the data as a array, we find it is easier to manipulate into the desired form for deeper analysis.

```sql
SELECT
    interval_end_local as hour_end,
    settlement_point_name,
    qse,
    energy_only_offer_curve
FROM
    ercot_dam_energy_only_offers_60_day
WHERE
    settlement_point_name = 'HB_NORTH'
    AND
    interval_start_local::DATE = '2024-12-01'
ORDER BY 
    hour_end ASC;

```

<figure><img src="/files/8c4pIi2NjrsA9ZM3skom" alt=""><figcaption></figcaption></figure>

### Reorganizing to columns to look like ERCOT source data

If you prefer to look at the curve as columns, you can do a query like this. Because there could be up to 10 points on the curve, you will see null values for offers that have less

```sql
SELECT
    interval_end_local AS hour_end,
    settlement_point_name,
    qse,
    -- Access the elements within the JSON array with MW first and then price
    energy_only_offer_curve[0][0]::FLOAT AS mw_1,
    energy_only_offer_curve[0][1]::FLOAT AS price_1,
    energy_only_offer_curve[1][0]::FLOAT AS mw_2,
    energy_only_offer_curve[1][1]::FLOAT AS price_2,
    energy_only_offer_curve[2][0]::FLOAT AS mw_3,
    energy_only_offer_curve[2][1]::FLOAT AS price_3,
    energy_only_offer_curve[3][0]::FLOAT AS mw_4,
    energy_only_offer_curve[3][1]::FLOAT AS price_4,
    energy_only_offer_curve[4][0]::FLOAT AS mw_5,
    energy_only_offer_curve[4][1]::FLOAT AS price_5,
    energy_only_offer_curve[5][0]::FLOAT AS mw_6,
    energy_only_offer_curve[5][1]::FLOAT AS price_6,
    energy_only_offer_curve[6][0]::FLOAT AS mw_7,
    energy_only_offer_curve[6][1]::FLOAT AS price_7,
    energy_only_offer_curve[7][0]::FLOAT AS mw_8,
    energy_only_offer_curve[7][1]::FLOAT AS price_8,
    energy_only_offer_curve[8][0]::FLOAT AS mw_9,
    energy_only_offer_curve[8][1]::FLOAT AS price_9,
    energy_only_offer_curve[9][0]::FLOAT AS mw_10,
    energy_only_offer_curve[9][1]::FLOAT AS price_10
FROM
    ercot_dam_energy_only_offers_60_day
WHERE
    settlement_point_name = 'HB_NORTH'
    AND
    interval_start_local::DATE = '2024-12-01'
ORDER BY 
    hour_end ASC;
```

<figure><img src="/files/MBw7Ilr0w2bIJvgrPD0L" alt=""><figcaption></figcaption></figure>

### Reformatting each point on offer curve as a row

A common way to reshape the data is to put each offer curve point on a row

```sql
SELECT
    interval_end_local AS hour_end,
    settlement_point_name,
    qse,
    f.value[0]::FLOAT AS mw,
    f.value[1]::FLOAT AS price
FROM
    ERCOT_DAM_ENERGY_ONLY_OFFERS_60_DAY,
    LATERAL FLATTEN(input => energy_only_offer_curve) AS f
WHERE
    settlement_point_name = 'HB_NORTH'
    AND
    hour_end = '2024-12-01 01:00:00.000 -0600'
ORDER BY 
    hour_end, settlement_point_name, price, qse;
```

<figure><img src="/files/S4gfnfZImWsZedGYw2Y4" alt=""><figcaption></figcaption></figure>

### Build an offer curve of a specific interval

We can take the query above one step further by making an offer curve showing the total and cumulative amount offered at each price. As the cumulative amount increase, so does the price.

```sql
WITH TotalOfferByPrice AS (
    SELECT
        interval_end_local AS hour_end,
        settlement_point_name,
        f.value[1]::FLOAT AS price,
        SUM(f.value[0]::FLOAT) AS total_mw
    FROM
        ercot_dam_energy_only_offers_60_day,
        LATERAL FLATTEN(input => energy_only_offer_curve) AS f
    WHERE
        settlement_point_name = 'HB_NORTH'
        AND interval_end_local = '2024-12-01 01:00:00.000 -0600'
    GROUP BY
        interval_end_local,
        settlement_point_name,
        f.value[1]::FLOAT
)

SELECT
    hour_end,
    settlement_point_name,
    price,
    total_mw,
    SUM(total_mw) OVER (PARTITION BY settlement_point_name, hour_end ORDER BY price ASC ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW) AS cumulative_mw
FROM
    TotalOfferByPrice
ORDER BY 
    cumulative_mw;
```

<figure><img src="/files/Lp59QeEtrznCZaFZvbM8" alt=""><figcaption></figcaption></figure>

This is just the tip of the iceberg when it comes to analysis of the offer and bid curve data. Let us know if there are any other examples you'd like to see!


# ERCOT Net Load Forecast and Actuals

The below examples show the SQL for calculating Actual and Forecasted Net Load in ERCOT using tables available our Snowflake Marketplace Listing.

## Net Load Actual

[ERCOT net load](https://www.gridstatus.io/datasets/ercot_net_load) shows the hourly net load across ERCOT. Net load is calculated by combining solar and wind generation and subtracting that from load. Net load is a clear metric that helps illustrate how much load is met by thermal and other dispatchable resources.

```sql
WITH solar_agg AS (
  SELECT
    ercot_solar_actual_and_forecast_by_geo_region_hourly.interval_start_local,
    -- actuals are repeated across multiple reports, 
    -- so we just select one using max()
    max(
      ercot_solar_actual_and_forecast_by_geo_region_hourly.gen_system_wide
    ) AS gen_system_wide
  FROM
    ercot_solar_actual_and_forecast_by_geo_region_hourly
  WHERE
    ercot_solar_actual_and_forecast_by_geo_region_hourly.gen_system_wide IS NOT NULL
  GROUP BY
    ercot_solar_actual_and_forecast_by_geo_region_hourly.interval_start_local
),
wind_agg AS (
  SELECT
    ercot_wind_actual_and_forecast_by_geo_region_hourly.interval_start_local,
    max(
      ercot_wind_actual_and_forecast_by_geo_region_hourly.gen_system_wide
    ) AS gen_system_wide
  FROM
    ercot_wind_actual_and_forecast_by_geo_region_hourly
  WHERE
    ercot_wind_actual_and_forecast_by_geo_region_hourly.gen_system_wide IS NOT NULL
  GROUP BY
    ercot_wind_actual_and_forecast_by_geo_region_hourly.interval_start_local
)
SELECT
  l.interval_start_local,
  l.interval_end_local,
  l.total AS load,
  s.gen_system_wide AS solar,
  w.gen_system_wide AS wind,
  l.total - s.gen_system_wide - w.gen_system_wide AS net_load
FROM
  ercot_load_by_forecast_zone l
  LEFT JOIN solar_agg s ON l.interval_start_local = s.interval_start_local
  LEFT JOIN wind_agg w ON l.interval_start_local = w.interval_start_local
WHERE
  l.total IS NOT NULL
ORDER BY
  l.interval_start_local DESC
LIMIT 1000;
```

<figure><img src="/files/gw4nbw158nAB3akAGioL" alt=""><figcaption></figcaption></figure>

## Net Load Forecast

[ERCOT net load forecast](https://www.gridstatus.io/datasets/ercot_net_load_forecast) is the forecasted net load levels for the current day and next six days in ERCOT. This is calculated by combining forecasted wind and solar generation and subtracting that from load forecasts. Net load is a clear metric that helps illustrate how much load is met by thermal and other dispatchable resources, which is particularly valuable as the net load peak has grown increasingly volatile.

```sql
WITH load AS (
  SELECT
    ercot_load_forecast_by_forecast_zone.interval_start_local,
    ercot_load_forecast_by_forecast_zone.system_total AS load_forecast,
    ercot_load_forecast_by_forecast_zone.publish_time_local AS load_publish_time_local
  FROM
    ercot_load_forecast_by_forecast_zone
  WHERE
    ercot_load_forecast_by_forecast_zone.system_total IS NOT NULL
),
renewables AS (
  SELECT
    s.interval_start_local,
    s.interval_end_local,
    s.stppf_system_wide AS solar_forecast,
    w.stwpf_system_wide AS wind_forecast,
    s.publish_time_local AS solar_publish_time_local,
    w.publish_time_local AS wind_publish_time_local
  FROM
    ercot_solar_actual_and_forecast_by_geo_region_hourly s
    JOIN ercot_wind_actual_and_forecast_by_geo_region_hourly w ON s.interval_start_local = w.interval_start_local
    -- Round to the nearest minute to ensure matching intervals
    AND date_trunc('minute', s.publish_time_local) = date_trunc('minute', w.publish_time_local)
  WHERE
    s.stppf_system_wide IS NOT NULL
    AND w.stwpf_system_wide IS NOT NULL
)
SELECT
  r.interval_start_local,
  r.interval_end_local,
  l.load_forecast,
  r.solar_forecast,
  r.wind_forecast,
  l.load_forecast - r.solar_forecast - r.wind_forecast AS net_load_forecast,
  GREATEST(
    l.load_publish_time_local,
    r.solar_publish_time_local,
    r.wind_publish_time_local
  ) AS publish_time_local,
  l.load_publish_time_local,
  r.solar_publish_time_local,
  r.wind_publish_time_local
FROM
  renewables r
  JOIN load l ON r.interval_start_local = l.interval_start_local
  -- Solar and wind forecasts are published at XX:55, so get the load forecast from XX:30
  AND date_trunc('minute', l.load_publish_time_local) = (
    date_trunc('minute', r.solar_publish_time_local) - interval '25 minutes'
  )
WHERE
  l.load_forecast IS NOT NULL
ORDER BY
  r.interval_start_local DESC
LIMIT 1000;
```

<figure><img src="/files/yBToiaZc3oShunvw3wfx" alt=""><figcaption></figcaption></figure>


# Priority Datasets on Snowflake

Typically, prioritizing data updates to Snowflake isn't necessary. However, during periods of limited throughput, such as data backfills, these priority datasets are updated first.

By adopting this prioritization strategy, we can better maintain low-latency synchronization and reliability for our most critical datasets used by customers.

{% hint style="info" %}
If there is a dataset you would like to see added, please reach out to us.
{% endhint %}

### CAISO

CAISO\_FUEL\_MIX\
CAISO\_LMP\_DAY\_AHEAD\_HOURLY

### ERCOT

ERCOT\_AS\_PRICES\
ERCOT\_AS\_REPORTS\
ERCOT\_ENERGY\_STORAGE\_RESOURCES\
ERCOT\_HOURLY\_RESOURCE\_OUTAGE\_CAPACITY\_REPORTS\
ERCOT\_LOAD\_FORECAST\
ERCOT\_LOAD\_FORECAST\_BY\_FORECAST\_ZONE\
ERCOT\_LOAD\_FORECAST\_BY\_WEATHER\_ZONE\
ERCOT\_REAL\_TIME\_AS\_MONITOR\
ERCOT\_SHORT\_TERM\_SYSTEM\_ADEQUACY\
ERCOT\_SOLAR\_ACTUAL\_AND\_FORECAST\_BY\_GEO\_REGION\_HOURLY\
ERCOT\_SOLAR\_ACTUAL\_AND\_FORECAST\_HOURLY\
ERCOT\_SPP\_DAY\_AHEAD\_HOURLY\
ERCOT\_SPP\_REAL\_TIME\_15\_MIN\
ERCOT\_TEMPERATURE\_FORECAST\_BY\_WEATHER\_ZONE\
ERCOT\_WIND\_ACTUAL\_AND\_FORECAST\_BY\_GEO\_REGION\_HOURLY\
ERCOT\_WIND\_ACTUAL\_AND\_FORECAST\_HOURLY

### ISONE

ISONE\_LMP\_DAY\_AHEAD\_HOURLY\
ISONE\_LMP\_REAL\_TIME\_5\_MIN

### MISO

MISO\_LOAD\
MISO\_LMP\_REAL\_TIME\_5\_MIN\
MISO\_LMP\_REAL\_TIME\_5\_MIN\_EX\_POST\_PRELIM\
MISO\_LMP\_DAY\_AHEAD\_HOURLY\
MISO\_LMP\_REAL\_TIME\_HOURLY\_EX\_POST\_FINAL\
MISO\_LMP\_REAL\_TIME\_HOURLY\_FINAL\
MISO\_LMP\_REAL\_TIME\_5\_MIN\_EX\_POST\_FINAL\
MISO\_LMP\_REAL\_TIME\_5\_MIN\_EX\_ANTE\
MISO\_LMP\_REAL\_TIME\_HOURLY\_PRELIM\
MISO\_LMP\_REAL\_TIME\_HOURLY\_EX\_POST\_PRELIM\
MISO\_LMP\_DAY\_AHEAD\_HOURLY\_EX\_ANTE\
MISO\_LMP\_DAY\_AHEAD\_HOURLY\_EX\_POST

### NYISO

NYISO\_FUEL\_MIX\
NYISO\_LMP\_DAY\_AHEAD\_HOURLY\
NYISO\_LMP\_REAL\_TIME\_5\_MIN

### PJM

PJM\_LMP\_DAY\_AHEAD\_HOURLY\
PJM\_LOAD

### SPP

SPP\_LMP\_DAY\_AHEAD\_HOURLY\
SPP\_LMP\_REAL\_TIME\_5\_MIN\
SPP\_LMP\_REAL\_TIME\_WEIS

<br>


# Embed Charts via IFrames

Embed Grid Status charts in your applications with iframes.

Iframe embeds are a low-code way to add Grid Status data and visuals to your applications.

{% hint style="success" %}
Iframe embeds are available only on Enterprise plans. Contact <contact@gridstatus.io> to add embeds to your account.
{% endhint %}

<figure><img src="/files/OB0atIE0pKTd40IUnS7R" alt="Example dashboard with Grid Status iframe embeds"><figcaption><p>Build your own app or dashboard using charts from Grid Status.</p></figcaption></figure>

## How it works

To embed a chart, start with a publicly available Grid Status chart URL and convert it to an embed URL:

1. Change `/charts/...` to `/embed/charts/...`.
2. Add `embed_key=<your_embed_key>` to the query string.
3. Use the resulting URL as the `src` for an iframe.

Use the embed key provided for your account. Each customer should use their own embed key.

## Prebuilt chart examples

### Fuel Mix

Original chart URL:

```
https://www.gridstatus.io/charts/fuel-mix?iso=caiso
```

Embed URL:

```
https://www.gridstatus.io/embed/charts/fuel-mix?iso=caiso&embed_key=<your_embed_key>
```

### Area Control Error

Original chart URL:

```
https://www.gridstatus.io/charts/area-control-error?iso=pjm
```

Embed URL:

```
https://www.gridstatus.io/embed/charts/area-control-error?iso=pjm&embed_key=<your_embed_key>
```

### Storage

Original chart URL:

```
https://www.gridstatus.io/charts/storage?iso=ercot
```

Embed URL:

```
https://www.gridstatus.io/embed/charts/storage?iso=ercot&embed_key=<your_embed_key>
```

### LMP

Original chart URL:

```
https://www.gridstatus.io/charts/lmp?iso=pjm&location=PJM-RTO
```

Embed URL:

```
https://www.gridstatus.io/embed/charts/lmp?iso=pjm&location=PJM-RTO&embed_key=<your_embed_key>
```

## Custom chart example

Custom charts use the same pattern. Change `/charts/new` to `/embed/charts/new` and add your embed key to the query string.

Original chart URL:

```
https://www.gridstatus.io/charts/new?graph_type=time_series&graph_settings={%22showLegend%22:true,%22enableZoomAndPan%22:false,%22graphFrequency%22:%22auto-linear%22}&table_settings={%22transposeTable%22:false,%22pinFirstColumn%22:true,%22sortColumn%22:%22Timestamp%22,%22sortDirection%22:%22desc%22,%22roundDecimals%22:2}&graph_series=[{%22yAxisIndex%22:0,%22data%22:{%22datasetId%22:%22ercot_spp_real_time_15_min%22,%22subseries_index_column%22:%22location%22,%22subseries_index_value%22:%22HB_HUBAVG%22,%22field%22:%22spp%22,%22resample_function%22:%22mean%22,%22externalSourceId%22:null,%22name%22:%22ERCOT+SPP+Real+Time+15+Min%22},%22seriesType%22:%22line%22,%22showSymbol%22:false,%22symbol%22:%22circle%22,%22lineStyleType%22:%22solid%22,%22connectNulls%22:true,%22seriesColor%22:%22%23276E0E%22,%22strokeWidth%22:2,%22lineStep%22:%22auto%22,%22name%22:%22%22,%22stackGroup%22:false},{%22yAxisIndex%22:1,%22data%22:{%22datasetId%22:%22ercot_fuel_mix%22,%22subseries_index_column%22:null,%22subseries_index_value%22:null,%22field%22:%22solar%22,%22resample_function%22:%22mean%22,%22externalSourceId%22:null,%22name%22:%22ERCOT+Fuel+Mix%22},%22seriesType%22:%22bar%22,%22showSymbol%22:false,%22symbol%22:%22circle%22,%22lineStyleType%22:%22solid%22,%22connectNulls%22:true,%22seriesColor%22:%22%23D77E25%22,%22strokeWidth%22:2,%22lineStep%22:%22auto%22,%22name%22:%22%22,%22stackGroup%22:false}]&y_axis_settings={}&secondary_y_axis_settings={}&reference_marks=[]
```

Embed URL:

```
https://www.gridstatus.io/embed/charts/new?graph_type=time_series&graph_settings={%22showLegend%22:true,%22enableZoomAndPan%22:false,%22graphFrequency%22:%22auto-linear%22}&table_settings={%22transposeTable%22:false,%22pinFirstColumn%22:true,%22sortColumn%22:%22Timestamp%22,%22sortDirection%22:%22desc%22,%22roundDecimals%22:2}&graph_series=[{%22yAxisIndex%22:0,%22data%22:{%22datasetId%22:%22ercot_spp_real_time_15_min%22,%22subseries_index_column%22:%22location%22,%22subseries_index_value%22:%22HB_HUBAVG%22,%22field%22:%22spp%22,%22resample_function%22:%22mean%22,%22externalSourceId%22:null,%22name%22:%22ERCOT+SPP+Real+Time+15+Min%22},%22seriesType%22:%22line%22,%22showSymbol%22:false,%22symbol%22:%22circle%22,%22lineStyleType%22:%22solid%22,%22connectNulls%22:true,%22seriesColor%22:%22%23276E0E%22,%22strokeWidth%22:2,%22lineStep%22:%22auto%22,%22name%22:%22%22,%22stackGroup%22:false},{%22yAxisIndex%22:1,%22data%22:{%22datasetId%22:%22ercot_fuel_mix%22,%22subseries_index_column%22:null,%22subseries_index_value%22:null,%22field%22:%22solar%22,%22resample_function%22:%22mean%22,%22externalSourceId%22:null,%22name%22:%22ERCOT+Fuel+Mix%22},%22seriesType%22:%22bar%22,%22showSymbol%22:false,%22symbol%22:%22circle%22,%22lineStyleType%22:%22solid%22,%22connectNulls%22:true,%22seriesColor%22:%22%23D77E25%22,%22strokeWidth%22:2,%22lineStep%22:%22auto%22,%22name%22:%22%22,%22stackGroup%22:false}]&y_axis_settings={}&secondary_y_axis_settings={}&reference_marks=[]&embed_key=<your_embed_key>
```

## Iframe example

```html
<iframe
  src="https://www.gridstatus.io/embed/charts/fuel-mix?iso=caiso&embed_key=YOUR_EMBED_KEY"
  width="100%"
  height="600"
  style="border: 0;"
  loading="lazy"
></iframe>
```

This is one common iframe configuration. Adjust the iframe attributes, height, loading behavior, and surrounding layout to fit your application.

## Limitations

Embedded charts have the same permissions as anonymous Grid Status users.


# LMP Dataset Overviews

Locational Marginal Prices (LMPs) are a core feature of US power markets, designed to direct investment and guide operations through efficient price signals.

While the overarching structure of LMPs are similar from market to market, their implementation and provided data varies in each region. This document will serve as grounding in some market discrepancies as well the available data.&#x20;

Unless otherwise noted, "final" prices used in settlements are the standard day-ahead hourly and real-time five-minute values. This varies by market, and you should check with your scheduling coordinator, settlements department, and the ISO itself as this information may change. &#x20;

Currently, we collect at least the basics (and likely more) from each ISO. Some markets have complex and idiosyncratic LMP datasets beyond real-time five-minute and day-ahead hourly. We are constantly working to integrate those datasets, prioritizing based on customer requests. If there are particular datasets you want to see, reach out at <contact@gridstatus.io>.

### Electric Reliability Council of Texas (ERCOT)

At a high level, price data in ERCOT is divided into two categories: LMPs and settlement point prices. As of the end of 2024, ERCOT has more than 18,000 prices buses, but less than 1,000 settlement points.&#x20;

Generally, SPP prices are useful for analyzing settlement prices for existing resources and comparison to Hub and Zone prices. Bus-based LMPs are useful to understand the entirety of ERCOT's system or prospect for new development locations. You won't find Hubs or Zones in by bus datasets, only settlement point data.

One major difference between ERCOT and other markets is the lack of LMP components in the data published by the market. The congestion component can be calculated as the difference between price at a particular location and either Hub or Bus average (we use Hub to show ERCOT congestion on our nodal price map). ERCOT ignores losses, and as such there is no ready derivation for outside observers.

**LMPs**

LMPs are provided per bus and settlement point. They are hourly in the day-ahead, nominally five-minutes in real-time, and also have an indicative (forecast) pass. All LMP by Bus datasets include one location type: *electrical bus*. LMPs for Settlement Points include LMPs for other elements, such as *Load Zones*, *Resource Nodes*, *DC Ties*, and *Trading Hubs*.

* [ERCOT LMP By Bus](https://www.gridstatus.io/datasets/ercot_lmp_by_bus) - real-time LMPs by bus, typically produced by SCED on a five-minute schedule.
* [ERCOT LMP By Bus DAM](https://www.gridstatus.io/datasets/ercot_lmp_by_bus_dam) - day-ahead LMPs, produced for each bus in hourly intervals&#x20;
* [ERCOT LMP By Settlement Point](https://www.gridstatus.io/datasets/ercot_lmp_by_settlement_point) - real-time LMPs by settlement point, typically produced by SCED on a five-minute schedule.
* [ERCOT Indicative LMP by Settlement Point](https://www.gridstatus.io/datasets/ercot_indicative_lmp_by_settlement_point) - Every five minutes ERCOT publishes a set of SCED-RTD indicative LMPs for the following 12 intervals.&#x20;

**Settlement Point Prices**

Other than only being provided for settlement points, the largest difference is in real-time where settlement point prices are derived from LMPs as well as price adders to calculate 15-minute prices used in settlements. SPP location types include: *Load Zones*, *Resource Nodes*, *DC Ties*, and *Trading Hubs*.&#x20;

* [ERCOT SPP Real Time 15 Min](https://www.gridstatus.io/datasets/ercot_spp_real_time_15_min) - Real-time, 15-minute settlement point prices for settlement points in ERCOT.
* [ERCOT SPP Day Ahead Hourly](https://www.gridstatus.io/datasets/ercot_spp_day_ahead_hourly) - Day-ahead, hourly settlement point prices for settlement points in ERCOT.&#x20;
* [ERCOT SPP Real Time Price Corrections](https://www.gridstatus.io/datasets/ercot_spp_real_time_price_corrections) - ERCOT-published price corrections for the real-time SPP series.
* [ERCOT SPP Day Ahead Price Corrections](https://www.gridstatus.io/datasets/ercot_spp_day_ahead_price_corrections) - ERCOT-published price corrections for the day-ahead SPP series.

### New York ISO (NYISO)

LMPs are properly called Location-based marginal prices (LBMPs) in New York as those involved in the market's conception identified locational as grammatically incorrect. We use the generic LMP nomenclature, even in NYISO, but it's useful to be aware of this difference when reviewing ISO documents.

NYISO is unique among US RTO/ISOs in that it only calculates prices for a references bus, load zones, external interfaces, and generators. It does not price at buses. This means that despite a smaller market (ISO-NE), NYISO LMP data is the smallest in terms of row count.

Another distinguishing element is present in NYISO's raw notation. In NYISO LMPs, a negative congestion component results in a higher LMP value, which is the opposite of other ISOs. Thus, we flip the sign on the congestion component before inserting into our database to maintain consistency with other ISOs. This means that in our database, LMP = Energy + Congestion + Loss

* [NYISO LMP Real Time 5 Min](https://www.gridstatus.io/datasets/nyiso_lmp_real_time_5_min) - Real-time, typically five-minute LMPs for locations in NYISO. Similar to other markets, the five-minute pricing pass can generate off-interval pricing under specific conditions. Produced from the Real-Time Dispatch (RTD) process.
* [NYISO LMP Day Ahead Hourly](https://www.gridstatus.io/datasets/nyiso_lmp_day_ahead_hourly) - Day-ahead, hourly LMPs for locations in NYISO. &#x20;
* [NYISO LMP Real Time 15 Min](https://www.gridstatus.io/datasets/nyiso_lmp_real_time_15_min) - Properly Real Time Commitment (RTC) values. RTC Runs every 15 minutes and looks ahead 2.5 hours. RTC runs are only binding for commitment and then only at the beginning of a run's output, with the remainder advisory. This process is similar to the one which produces ERCOT's Indicative SPP prices. 5-minute RTD prices are the prices used in calculating settlements.&#x20;

### PJM Interconnection (PJM)

PJM has the typical five-minute real-time and hourly day-ahead LMP data as well as feeds with "Settlements Verified" LMPs for the aggregate and zonal PNodes used for settlement. The non-verified feeds contain all locations types, including *Zone*, *Hub*, *Aggregate*, *Interface*, *EHV*, *Bus*, and others.&#x20;

* [PJM LMP Real Time 5 Min](https://www.gridstatus.io/datasets/pjm_lmp_real_time_5_min) - Real-time, five-minute LMPs as reported by PJM for all locations.&#x20;
* [PJM LMP Real Time Hourly](https://www.gridstatus.io/datasets/pjm_lmp_real_time_hourly) - Real-time, hourly LMPs as reported by PJM for all locations.
* [PJM Settlements Verified LMP 5 Min](https://www.gridstatus.io/datasets/pjm_settlements_verified_lmp_5_min) - Verified, real-time, five-minute LMPs for the aggregate and zonal PNodes used for settlement in PJM. Does not include the location type *Bus*.&#x20;
* [PJM LMP IT SCED 5 Min](https://www.gridstatus.io/datasets/pjm_lmp_it_sced_5_min) - Five-minute real-time prices from the Intermediate-Term Security Constrained Economic Dispatch engine ( IT-SCED). The prices in this dataset cover individual ties between bordering areas and PJM as well as aggregate prices for ties between PJM and MISO and all PJM ties.
* [PJM LMP Day Ahead Hourly](https://www.gridstatus.io/datasets/pjm_lmp_day_ahead_hourly) - Day-ahead, hourly, LMPs reported by PJM for all locations.&#x20;
* [PJM Settlements Verified LMP Hourly](https://www.gridstatus.io/datasets/pjm_settlements_verified_lmp_hourly) - Verified, day-ahead, hourly LMPs for the aggregate and zonal PNodes used for settlement in PJM. Does not include the location type *Bus*.&#x20;

### Southwest Power Pool (SPP)

Like ERCOT, SPP divides price data into by *bus* and by settlement point and other aggregates. The non-bus price datasets include *Settlement Location*, *Interface*, and *Hub* location types. Pricing by bus includes all nodes in SP's commercial model. SPP also administers the Western Energy Imbalance Service market (WEIS), which is included in the list below.&#x20;

* [SPP LMP Real Time 5 min](https://www.gridstatus.io/datasets/spp_lmp_real_time_5_min)  - Real-time, five-minute LMPs reported by SPP. Does not include buses. &#x20;
* [SPP LMP Real Time By Bus](https://www.gridstatus.io/datasets/spp_lmp_real_time_by_bus) - Real-time, five-minute LMPs reported by SPP for buses.&#x20;
* [SPP LMP Day Ahead Hourly](https://www.gridstatus.io/datasets/spp_lmp_day_ahead_hourly) - Day-ahead, hourly LMPs reported by SPP. Does not include buses.&#x20;
* SPP LMP Day Ahead By Bus - Day-ahead, hourly LMPs reported by SPP for buses.&#x20;
* [SPP LMP Real Time WEIS](https://www.gridstatus.io/datasets/spp_lmp_real_time_weis) - Real-time, five-minute LMP data for WEIS. WEIS is a real-time only balancing market administered by SPP in the Western Interconnect.&#x20;

### California ISO (CAISO)

* [CAISO LMP Real Time 5 Min](https://www.gridstatus.io/datasets/caiso_lmp_real_time_5_min) - Real-time, five-minute LMPs as reported by CAISO for all locations in CAISO. This includes locations in CAISO-administered real-time balancing markets.&#x20;
* [CAISO LMP Day Ahead Hourly](https://www.gridstatus.io/datasets/caiso_lmp_day_ahead_hourly) - Day-ahead, hourly LMPs as reported by CAISO. Some non-CAISO western locations are included due to transmission ties and specific contracts.&#x20;
* [CAISO LMP Real Time 15 Min](https://www.gridstatus.io/datasets/caiso_lmp_real_time_15_min) - The 15-minute market in CAISO is conducted by utilizing Real-Time Unit Commitment pass, RTUC (similar to NYISO's RTC). Timing gets complicated, so here are two snippets from CAISO's tariff. First, one on conducting the fifteen-minute market: <br>

> The CAISO conducts the Fifteen Minute Market using the second interval of each RTUC run horizon as follows: (1) at approximately 7.5 minutes prior to the first Trading Hour, for T-45 minutes to T+60 minutes where the binding interval is T-30 to T-15; (2) at approximately 7.5 minutes into the current hour for T-30 minutes to T+60 minutes where the binding interval is T-15 to T; (3) at approximately 22.5 minutes into the current hour for T-15 minutes to T+60 minutes for the binding interval T to T+15; and (4) at approximately 37.5 minutes into the current hour for T to T+60 minutes for the binding interval T+15 to T+30, where T is the beginning of the next Trading Hour.

and a second on RTUC in general:

> RTUC is run at the following time intervals: (1) at approximately 12 minutes prior to the first Trading Hour, to serve as the HASP run, for T-45 minutes to T+60 minutes; (2) at approximately 7.5 minutes into the current hour for T30 minutes to T+60 minutes; (3) at approximately 22.5 minutes into the current hour for T-15 minutes to T+60 minutes; and (4) at approximately 37.5 minutes into the current hour for T to T+60 minutes, where T is the beginning of the next Trading Hour. The HASP is a special RTUC run that is performed at approximately 67.5 minutes before each Trading Hour and has the additional responsibility of pre-dispatching Energy and awarding Ancillary Services for HASP Block Intertie Schedules.

### Midcontinent ISO (MISO)

MISO's naming conventions around LMPs are special. Both prelim and final are present, but so are ex ante and ex post. That right, MISO brings ceremony to LMPs with Latin. Ex ante meaning "before" and ex post meaning "after". Ex ante prices come from the SCED process, ex post prices are then calculated from the SCED-Pricing process. Final prices are published in thee days following the market day, these are the prices which are used in settlements.

In MISO's documentation you will also come across the term ELMP, in which the "E" stands for Extended. Their implementation of ELMPs began in 2015 and addressed issues identified as early as 2005 by MISO's IMM (never let it be said that ISO software changes are easy). To put it simply, ELMPs allow fast start resources to set the price, under the original system these resources would not be picked up as marginal and so the system would come to inefficient and more expensive outcomes.&#x20;

* [MISO LMP Day Ahead Hourly Ex Ante](https://www.gridstatus.io/datasets/miso_lmp_day_ahead_hourly_ex_ante) - Day-ahead, hourly, Ex-Ante, LMPs publishing by MISO prior to the operating day. Ex-Ante LMPs are published in the early afternoon of the day prior to the market day, several hours before the Ex-Post day-ahead LMPs.
* [MISO LMP Day Ahead Hourly Ex Post](https://www.gridstatus.io/datasets/miso_lmp_day_ahead_hourly_ex_post) - Day-ahead, hourly, Ex-Post, LMPs publishing by MISO prior to the operating day.
* [MISO LMP Real Time 5 Min Ex Ante](https://www.gridstatus.io/datasets/miso_lmp_real_time_5_min_ex_ante) - Ex-Ante, real-time, five-minute, LMPs in MISO.
* [MISO LMP Real Time 5 Min Ex Post Prelim](https://www.gridstatus.io/datasets/miso_lmp_real_time_5_min_ex_post_prelim) - Preliminary Ex-Post real-time five-minute LMPs in MISO.
* [MISO LMP Real Time 5 Min Ex Post Final](https://www.gridstatus.io/datasets/miso_lmp_real_time_5_min_ex_post_final) - Final Ex Post real-time five-minute LMPs in MISO.
* [MISO LMP Real Time Hourly Ex Post Prelim](https://www.gridstatus.io/datasets/miso_lmp_real_time_hourly_ex_post_prelim) - Preliminary, hourly, real-time, Ex Post LMPs from MISO.
* [MISO LMP Real Time Hourly Ex Post Final](https://www.gridstatus.io/datasets/miso_lmp_real_time_hourly_ex_post_final) - Final hourly real-time LMPs for each Pnode in MISO.

### ISO New England (ISO-NE)

For real-time hourly preliminary prices, the values are published as soon as practicable after the operating hour has concluded.  5-minute real-time prices are made available in approximately real-time.

* [ISONE LMP Real Time 5 Min Prelim](https://www.gridstatus.io/datasets/isone_lmp_real_time_5_min_prelim) - Preliminary, real-time five-minute LMPs.
* [ISONE LMP Day Ahead Hourly](https://www.gridstatus.io/datasets/isone_lmp_day_ahead_hourly) - Day-ahead hourly LMPs, includes all locations in ISO-NE&#x20;
* [ISONE LMP Real-Time 5 min Final](https://www.gridstatus.io/datasets/isone_lmp_real_time_5_min_final) - Final, real-time, five-minute LMPs.
* [ISONE LMP Real-Time Hourly Final](https://www.gridstatus.io/datasets/isone_lmp_real_time_hourly_final) - Final, real-time, hourly LMPs.
* [ISONE LMP Real-Time Hourly Prelim](https://www.gridstatus.io/datasets/isone_lmp_real_time_hourly_prelim) - Final, real-time, hourly LMPs.

### Independent Electricity System Operator (IESO)

On May 1st, 2025, IESO's Market Renewal Program (MRP)  introduced nodal pricing and LMPs to the broader market (learn more at our blog [here](https://blog.gridstatus.io/market-renewal-in-ontario/)).

This change shifted Ontario from its previous uniform market-wide clearing prices to a nodal pricing system like ISOs and RTOs in the United States. This new system generates both hourly day-ahead and five-minute real-time prices. LMPs are now calculated for generation, external ties, demand response aggregations (DRAs), virtual zones, and select buses.&#x20;

One notable holdover from the previous market is the Ontario Zonal Price (ONZP). The ONZP is a province-wide load weighted LMP that will be used to settle transactions for participants such as passive loads, similar to the previous market's hourly Ontario energy price (HOEP).&#x20;

Day Ahead data should fill after the successful completion of the day ahead model run, approximately 13:30 ET.&#x20;

MRP also introduced virtual trading to Ontario. Nine virtual zones are assigned both day ahead and real time LMPs, which will be used to settle virtual transactions. Market participants make financially binding day ahead transactions that are settled to the real time zonal price. Nodal-level virtual trading is not a part of the market, which is similar to NYISO.

To obtain a complete view of either day-ahead or real-time prices across all facets of the system, the nodal, virtual zone, intertie and Ontario-wide LMPs are all required.

* [IESO LMP Day Ahead Hourly LMPs](http://gridstatus.io/datasets/ieso_lmp_day_ahead_hourly) - Day-ahead hourly LMPs broken into component costs for generators, selected buses, and DRAs.&#x20;
* [IESO LMP Day Ahead Hourly Virtual Zonal](http://gridstatus.io/datasets/ieso_lmp_day_ahead_hourly_virtual_zonal) - Day-ahead hourly LMPs for Ontario’s nine virtual trading zones broken into component costs. IESO's virtual zones are East, Essa, Niagara, Northeast, Northwest, Ottawa, Southwest, Toronto, and West.
* [IESO LMP Day Ahead Hourly Ontario Zonal](http://gridstatus.io/datasets/ieso_lmp_day_ahead_hourly_ontario_zonal) - Day ahead hourly LMPs and their component costs for the ONZP.
* [IESO LMP Day Ahead Hourly Intertie](http://gridstatus.io/datasets/ieso_lmp_day_ahead_hourly_intertie) - Day-ahead hourly LMPs and their component costs for Ontario’s intertie points. Interfaces by neighboring region
  * **Québec (PQ)**: PQ.BEAUHARNOIS\_PQBE, PQ.BRYSON\_PQXY, PQ.KIPAWA\_PQHZ, PQ.MACLAREN\_PQDA, PQ.MASSON\_PQHA, PQ.OUTAOUAIS\_PQAT, PQ.PAUGAN\_PQPC, PQ.QUYON\_PQQC, PQ.RAPIDDESISLE\_PQDZ
  * **New York ISO (NY)**: EC.MARITIMES\_NYSI, NY.ROSETON\_NYSI
  * **Manitoba (MB)**: MB.SEVENSISTERS\_MBSK, MB.WHITESHELL\_MBSI
  * **Michigan (MI)**: MI.LUDINGTON\_MISI, MI.LUDINGTON.SOURCE, WC.PRAIRERANGES\_MISI, MD.CALVERTCLIFF\_MISI, MD.CALVERTCLIFF\_NYSI
  * **Minnesota (MN)**: MN.INTFALLS\_MNSI
* [IESO LMP Day Ahead Hourly All](http://gridstatus.io/datasets/ieso_lmp_day_ahead_hourly_all)- Day-ahead hourly LMPs and their component costs for all pricing locations in Ontario, including virtual zones, interties, and the Ontario Zonal Price.
* [IESO LMP Real Time 5 Min](http://gridstatus.io/datasets/ieso_lmp_real_time_5_min) - Real-time 5 minute nodal LMPs and their component costs.
* [IESO LMP Real Time 5 Min Virtual Zonal](http://gridstatus.io/datasets/ieso_lmp_real_time_5_min_virtual_zonal) - Real-time 5 minute LMPs for Ontario’s nine virtual trading zones broken into component costs. IESO's virtual zones are East, Essa, Niagara, Northeast, Northwest, Ottawa, Southwest, Toronto, and West.
* [IESO LMP Real Time 5 Min Ontario Zonal](http://gridstatus.io/datasets/ieso_lmp_real_time_5_min_ontario_zonal) - Real-time 5 minute LMPs and their component costs for the ONZP.
* [IESO LMP Real Time 5 Min Intertie](http://gridstatus.io/datasets/ieso_lmp_real_time_5_min_intertie) - Real-time 5 minute LMPs and their component costs for Ontario’s intertie points. Interfaces by neighboring region
  * **Québec (PQ)**: PQ.BEAUHARNOIS\_PQBE, PQ.BRYSON\_PQXY, PQ.KIPAWA\_PQHZ, PQ.MACLAREN\_PQDA, PQ.MASSON\_PQHA, PQ.OUTAOUAIS\_PQAT, PQ.PAUGAN\_PQPC, PQ.QUYON\_PQQC, PQ.RAPIDDESISLE\_PQDZ
  * **New York ISO (NY)**: EC.MARITIMES\_NYSI, NY.ROSETON\_NYSI
  * **Manitoba (MB)**: MB.SEVENSISTERS\_MBSK, MB.WHITESHELL\_MBSI
  * **Michigan (MI)**: MI.LUDINGTON\_MISI, MI.LUDINGTON.SOURCE, WC.PRAIRERANGES\_MISI, MD.CALVERTCLIFF\_MISI, MD.CALVERTCLIFF\_NYSI
  * **Minnesota (MN)**: MN.INTFALLS\_MNSI
* [IESO LMP Real Time 5 Min All](http://gridstatus.io/datasets/ieso_lmp_real_time_5_min_all)- Real time 5 minute LMPs and their cost components for all pricing locations in Ontario, including nodes, virtual zones, interties, and the Ontario Zonal Price.

\ <br>


# Independent Electricity System Operator (IESO)

Brief walkthrough of the IESO market and ways to use Grid Status products and data to monitor and analyze wholesale electricity market outcomes in Ontario.

<figure><img src="/files/AsWKKGnXpkjDmN1psSp8" alt=""><figcaption></figcaption></figure>

The Independent Electricity System Operator (IESO) is the market operator for Ontario. IESO today is a crown corporation that fills the roles of ISO/RTO, LSE, and planning and procurement authority.  While IESO was formed around the same time as deregulation led to ISOs and RTOs in the US, their market structure heavily relied on out of market payments and systemwide pricing until May 1st, 2025 when nodal pricing and a full two settlement system went into effect.

IESO’s structure is unique in North American power markets, acting as if its neighbor, NYISO, also contained the New York Power Authority (NYPA), the New York State Energy Research and Development Authority (NYSERDA), and were a state-owned corporation. Despite this, many market products largely resemble their US counterparts, so whether you've worked in NYISO, MISO, or PJM, the contours of IESO market should be familiar. However, this doesn't mean the market is without its quirks, so let's dig in.

{% hint style="info" %}
For a full list of our current IESO datasets, you can [filter our Data Catalog ](https://www.gridstatus.io/datasets?source=ieso)by the IESO market.\
\
For more detail on Market Renewal and IESO's history, check out our blog, [Market Renewal in Ontario: Navigating IESO's Shift to a Nodal System](https://blog.gridstatus.io/market-renewal-in-ontario/).
{% endhint %}

### Fuel Mix

A great way to quickly understand the ground state in a particular market is via the installed generation, and one way to get a sense of that is through [fuel mix data](https://www.gridstatus.io/datasets/ieso_fuel_mix), which is [charted](https://www.gridstatus.io/charts/fuel-mix?iso=ieso\&date=2025-04-21to2025-04-26) on the [IESO Live Page](https://www.gridstatus.io/live/ieso).

<figure><img src="/files/dd96PUfmyMrydby6XuZR" alt=""><figcaption></figcaption></figure>

IESO is a fairly unique region in terms of fuel mix, with \~75% of demand served by nuclear and hydro assets, while wind and gas make up most of the remainder. This fuel mix data is also unique, in that it is derived from [generator-level generation data](https://www.gridstatus.io/datasets/ieso_generator_report_hourly), which is provided by IESO in near real-time.

<figure><img src="/files/6OZaAllqe7tUDmliRqVB" alt=""><figcaption></figcaption></figure>

Most North American markets don't offer this kind of real-time insight, and it's a great tool for contextualizing specific outcomes in the market as they occur. This became even more useful with the addition of the nodal market, as participants could see the intraday impact of specific assets based on their location.

You can make charts or dashboards of generator sets in the Grid Status platform, but if you want to query a specific generator using the API, you can write a code snippet like this:

```python
from gridstatusio import GridStatusClient
import os

GS_KEY = os.environ["GS_API_KEY"]
client = GridStatusClient(GS_KEY)

df_gen = client.get_dataset(
    dataset = 'ieso_generator_report_hourly',
    start = '2025-02-19',
    end = '2025-02-28',
    filter_column = 'generator_name',
    filter_value = 'BELLE RIVER',
    timezone = 'US/Eastern',
    )
```

And if you wanted to plot the data:

```python
import matplotlib.pyplot as plt

# Apply dark background and increase font sizes
plt.style.use('dark_background')
plt.rcParams.update({
    'font.size': 16,
    'axes.labelsize': 18,
    'axes.titlesize': 20,
    'xtick.labelsize': 14,
    'ytick.labelsize': 14,
    'figure.figsize': (14, 6)
})

fuel_type = df_gen['fuel_type'].values[0]

# Create the plot
fig, ax = plt.subplots()

ax.plot(df_gen['interval_start_local'], df_gen['output_mw'], color='cyan', linewidth=2)

# Add labels and title
ax.set_title(f'Belle River ({fuel_type}) Output')
ax.set_xlabel(None)
ax.set_ylabel('MW')

# Improve x-axis readability
fig.autofmt_xdate()

# Add gridlines
ax.grid(True, which='both', linestyle='--', linewidth=0.5, alpha=0.7)

plt.tight_layout()
plt.show()
```

Which returns this chart.

<figure><img src="/files/CXSbC4Sluu1E40iHOeJC" alt=""><figcaption></figcaption></figure>

Ontario Power Generation (OPG) owns the bulk of the generating capacity in the province, and, like IESO, was split out from Ontario Hydro. On the transmission side, another sibling, Hydro One, maintains much of the physical network.&#x20;

### Prices

Previously, IESO had a single systemwide price, the Hourly Ontario Energy Price (HOEP), with some variation at the interchanges. Post-Market Renewal, the system has largely moved over to Locational Marginal Prices (LMPs). However, Ontarian quirks remain. To get a complete view of prices, the day-ahead and real-time each have [4 datasets](https://www.gridstatus.io/datasets?filter=lmp\&source=ieso): LMPs for nodes, interties, virtual zonal, and Ontario-wide. These are detailed in our [LMP guide](https://docs.gridstatus.io/data-guides#independent-electricity-system-operator-ieso). If you want complete pricing, we've prepared [real-time](https://www.gridstatus.io/datasets/ieso_lmp_real_time_5_min_all) and day-ahead datasets that combine the individual datasets for each set of prices.

With the introduction of a nodal market we've expanded our nodal map to cover Ontario.

<figure><img src="/files/wQCdaQidBzDBl2gHnPJI" alt=""><figcaption></figcaption></figure>

{% hint style="info" %}
While coordinates are not available by default in the API or Snowflake, [reach out](https://www.gridstatus.io/contact) if you're interested in access.
{% endhint %}

### Load

There are a [number of datasets](https://www.gridstatus.io/datasets?filter=load\&source=ieso) in IESO that have information on demand, including [five-minute load ](https://www.gridstatus.io/datasets/ieso_load)data from their *Realtime Constrained Totals* report.

IESO also publishes forecasts, in both [zonal](https://www.gridstatus.io/datasets/ieso_zonal_load_forecast_hourly) and [Ontario-wide](https://www.gridstatus.io/datasets/ieso_load_forecast_hourly) varieties. If we plot some of the series from forecast and actual demand together a big discrepancy between **market** and **Ontario** demand arises.

<figure><img src="/files/9A6FFoXEiYkSokuWVKuC" alt=""><figcaption></figcaption></figure>

The Ontario value is internal demand, while market total adds includes several elements omitted from Ontario alone. Exports tends to be a significant factor, as IESO is a net exporter in most intervals. The complete calculation for Ontario demand is:

*Total Energy + Total Generation Without Offers -Total Exports +Total Off Market +/- Over/Under*\
*Generation*

### The Adequacy Report

IESO publishes an [adequacy report](https://www.gridstatus.io/datasets/ieso_adequacy_report_forecast#dataset-columns) which contains:

> **information on Ontario's electricity requirements for today through 34 days out**&#x20;

Outages, capacity offered and forecast by type, interchange, demand, and more, this dataset may have the most columns of any in our catalog. It powers our IESO outages card.

<figure><img src="/files/tnQ9nHIgZ50qoptibve0" alt=""><figcaption></figcaption></figure>

And can be used to examine the difference between interchange offers and schedules

<figure><img src="/files/QNlz9neNAAqenxecCgOn" alt=""><figcaption></figcaption></figure>

This report is published multiple times a day - twice per hour for the current day, 13 times for the next day, and twice per day for future days. This means that the near-term data in particular can undergo meaningful shifts throughout the day.&#x20;

We can pull the data using python:

```python
from gridstatusio import GridStatusClient
import os

GS_KEY = os.environ["GS_API_KEY"]
client = GridStatusClient(GS_KEY)

df = client.get_dataset(
    dataset = 'ieso_adequacy_report_forecast',
    start = '2025-04-20',
    end = '2025-04-26',
    timezone = 'US/Eastern',
    )
df.columns

```

and then plot the forecasts of peak demand across that period of time:

```python
import pandas as pd
import matplotlib.pyplot as plt
from matplotlib.ticker import FuncFormatter

pivot = df.pivot_table(
    index='interval_start_local',
    columns='publish_time_local',
    values='ontario_peak_demand'
)

times = pivot.columns.sort_values()
cmap = plt.get_cmap('plasma')
colors = [cmap(i/(len(times)-1)) for i in range(len(times))]

plt.style.use('default')
plt.rcParams.update({
    'font.size': 14,
    'text.color': 'black',
    'axes.labelcolor': 'black',
    'xtick.color': 'black',
    'ytick.color': 'black',
    'figure.facecolor': 'white',
    'axes.facecolor':   'white',
})

# 5. Plot all lines without a legend
fig, ax = plt.subplots(figsize=(12, 6))
for t, col in zip(times, colors):
    ax.plot(pivot.index, pivot[t], color=col, linewidth=2)

# 6. Remove chart border
for spine in ax.spines.values():
    spine.set_visible(False)

ax.set_ylim(10000, 20000)
ax.grid(axis='y', linestyle='--', linewidth=0.5)
ymin, ymax = ax.get_ylim()
ax.axhline(y=ymin, color='black', linewidth=1)

ax.yaxis.set_major_formatter(FuncFormatter(lambda x, pos: f'{int(x/1000)}k'))
y_pos = ymax - 0.02 * (ymax - ymin)

oldest, newest = times[0], times[-1]
bbox_props = dict(boxstyle='round,pad=0.3', facecolor='lightgrey', edgecolor='none')
ax.text(
    pivot.index[0], y_pos,
    f'Oldest: {oldest.strftime("%Y-%m-%d %H:%M")}',
    va='top', ha='left',
    color=colors[0],
    fontsize=12,
    fontweight='bold',
    bbox=bbox_props
)
ax.text(
    pivot.index[-1], y_pos,
    f'Newest: {newest.strftime("%Y-%m-%d %H:%M")}',
    va='top', ha='right',
    color=colors[-1],
    fontsize=12,
    fontweight='bold',
    bbox=bbox_props
)

ax.set_title('Ontario Peak Demand by Publish Time', pad=16, color='black')
ax.set_xlabel(None)
ax.set_ylabel('MW')

plt.tight_layout()
plt.show()

```

And here's the plot.

<figure><img src="/files/QYnJuhMNm4mZr4eQyHuc" alt=""><figcaption></figcaption></figure>

To make this even easier, we recently lauched the beta verison of a new Forecast Analysis app.&#x20;

This new tool allows you to view forecast vintages and actuals in a graph, table, or both. Currently, we support IESO's Onatrio Load forecast, Wind and Solar, and total outages.&#x20;

<figure><img src="/files/UCchwAUZraj37p1POxgv" alt=""><figcaption></figcaption></figure>

Give the beta a test [here](https://www.gridstatus.io/forecast-analysis) and pass along any impressions and feedback!


# Preparing for RTC+B Transition

We know how sensitive your workflows are to disruptions, and we’ve taken extensive steps to ensure a smooth transition during the RTC+B cutover.

{% hint style="success" %}

### The RTC+B cutover is complete

We’ve started ingesting many new datasets and have updated our application
{% endhint %}

ERCOT will implement RTC+B (Real-Time Co-Optimizations plus Batteries) on December 5, 2025. This document outlines our approach to ensure a smooth transition for all of our customers.

We’ll update this document as new information comes in, so check back for the latest details. For any questions or issues, please email <support@gridstatus.io>.

### Expected Timeline

ERCOT plans to go live around midnight between December 4 and December 5, 2025.

ERCOT has noted that “systems may experience intermittent service interruptions during the implementation period,” so we advise planning for potential disruptions.

If reliability concerns arise (such as extreme weather), the backup date is one week later at midnight between December 11 and December 12, 2025.

### What’s Changing?

RTC+B restructures both the real-time and day-ahead markets. Instead of clearing energy and ancillary services separately, ERCOT will clear them together through a single co-optimized process. The project also updates how Energy Storage Resources are modeled, with ESRs now treated as one unified device in ERCOT’s systems.

These changes are wide-ranging and will alter how many reports and datasets are produced. We’ve reviewed all ERCOT working group materials and published documentation to prepare.

{% hint style="info" %}

### Dataset Changelog

To see detailed information on changes to datasets due to RTC+B, visit [RTC+B Dataset Changelog](/data-guides/ercot-rtc+b/dataset-changelog)
{% endhint %}

#### How We’re Handling the Transition

We’ve been tracking the RTC+B cutover closely and preparing across the stack. Here’s how we’re prioritizing the transition:

1. Maintain stability of all existing datasets
   1. Ensure current datasets keep working after the cutover.
   2. In cases where there is a new definition or calculation for a particular column, we will note it in the dataset description.
2. Handle modified reports
   1. Update handling of reports that add or drop columns under RTC+B.
3. Add datasets for new reports
   1. Trial versions of many reports are already live with dataset IDs ending in \_rtc\_b\_trial. View full list here: <https://www.gridstatus.io/datasets?filter=rtc_b>
   2. After the cutover, we’ll publish a new version of each dataset without that suffix to denote that it is the real data.
4. Retire old datasets
   1. Some legacy datasets won’t receive updates under RTC+B. We’ll keep them available for historical analysis, but they won’t get new data.
   2. Once everything is fully transitioned, we’ll retire and eventually remove the trial datasets.

### Live Page Dashboards

We will be releasing a new pre-built dashboard for monitoring real time AS data. You can see a preview of it with the trial data here: <https://www.gridstatus.io/live/ercot#rtc_b>

### Support

During the transition, if you notice issues or need assistance, please don’t hesitate to reach out.


# RTC+B Dataset Changelog

Information on changes to our datasets

### Modified Datasets

* [ERCOT Short-Term System Adequacy](https://www.gridstatus.io/datasets/ercot_short_term_system_adequacy) (`ercot_short_term_system_adequacy`)
  * The following columns have been added: `capacity_reg_up_total`, `capacity_reg_down_total`, `capacity_rrs_total`, `capacity_ecrs_total`, `capacity_nspin_total`, `capacity_reg_up_rrs_total`, `capacity_reg_up_rrs_ecrs_total`, `capacity_reg_up_rrs_ecrs_nspin_total`
* [ERCOT LMP with Adders by Settlement Point](https://www.gridstatus.io/datasets/ercot_lmp_with_adders_by_settlement_point)
  * We will add a column for `rtrdpa`&#x20;
  * Post-cutover the calculation for the `lmp_with_adders` column will be `lmp + rtrdpa` . The columns for the prior adders (`rtorpa` and `rtordpa`) will remain, but always be null going forward.
* [ERCOT SCED Generation Resource 60 Day](https://www.gridstatus.io/datasets/ercot_sced_gen_resource_60_day)
  * Added columns with data starting 2025-12-05 (prior to this columns are present but null):
    * `ramp_rate_up`
    * `ramp_rate_down`
    * `as_capability_regup`
    * `as_capability_regdown`
    * `as_capability_ecrs`
    * `as_capability_nonspin`
    * `as_awards_nonspin`
    * `as_awards_rrsffr`
    * `as_awards_rrspfr`
    * `as_awards_rrsufr`
    * `as_awards_ecrs`
    * `as_awards_regup`
    * `as_awards_regdown`
    * `as_capability_rrspf`
    * `as_capability_rrsff`
  * These columns will no longer have new data starting 2025-12-05:
    * `as_responsibility_for_rrs`
    * `as_responsibility_for_rrsffr`
    * `as_responsibility_for_nonspin`
    * `as_responsibility_for_regup`
    * `as_responsibility_for_regdown`
    * `as_responsibility_for_ecrs`
    * `hasl`
    * `lasl`
* [ERCOT SCED Load Resource 60 Day](https://www.gridstatus.io/datasets/ercot_sced_load_resource_60_day)
  * Added columns with data starting 2025-12-05 (prior to this, columns are present but all null):
    * `ramp_rate_up`
    * `ramp_rate_down`
    * `as_capability_regup`
    * `as_capability_regdown`
    * `as_capability_ecrs`
    * `as_capability_nonspin`
    * `as_awards_nonspin`
    * `as_awards_rrsffr`
    * `as_awards_rrspfr`
    * `as_awards_rrsufr`
    * `as_awards_ecrs`
    * `as_awards_regup`
    * `as_awards_regdown`
    * `self_provided_rrsffr`
    * `self_provided_rrsufr`
    * `self_provided_ecrs`
    * `as_capability_rrspf`
    * `as_capability_rrsff`
    * `as_capability_rrsuf`
  * These columns will no longer have new data starting 2025-12-05:
    * `as_responsibility_for_rrs`
    * `as_responsibility_for_rrsffr`
    * `as_responsibility_for_nonspin`
    * `as_responsibility_for_regup`
    * `as_responsibility_for_regdown`
    * `as_responsibility_for_ecrs`
    * `hasl`
    * `lasl`

### New Datasets

Here is a list of all new datasets related to RTC+B with links to their descriptions

#### MCPC

1. [ERCOT MCPC Real Time 15 Min](https://www.gridstatus.io/datasets/ercot_mcpc_real_time_15_min) (`ercot_mcpc_real_time_15_min`)
2. [ERCOT MCPC SCED](https://www.gridstatus.io/datasets/ercot_mcpc_sced) (`ercot_mcpc_sced`)
3. [ERCOT MCPC DAM](https://www.gridstatus.io/datasets/ercot_mcpc_dam) (`ercot_mcpc_dam`)
   1. replaces [ERCOT AS Prices](https://www.gridstatus.io/datasets/ercot_as_prices) (`ercot_as_prices)`
4. [ERCOT Indicative MCPC RTD](https://www.gridstatus.io/datasets/ercot_indicative_mcpc_rtd) (`ercot_indicative_mcpc_rtd`)

#### AS Disclosure Reports

1. [ERCOT AS Reports DAM](https://www.gridstatus.io/datasets/ercot_as_reports_dam) (`ercot_as_reports_dam`)
2. [ERCOT AS Reports SCED](https://www.gridstatus.io/datasets/ercot_as_reports_sced) (`ercot_as_reports_sced`)

#### Other

1. [ERCOT AS Total Capability](https://www.gridstatus.io/datasets/ercot_as_total_capability) (`ercot_as_total_capability`)
2. [ERCOT DAM Total AS Sold](https://www.gridstatus.io/datasets/ercot_dam_total_as_sold) (`ercot_dam_total_as_sold`)
3. [ERCOT Real Time Adders](https://www.gridstatus.io/datasets/ercot_real_time_adders) (`ercot_real_time_adders`)
   1. Replaces [ERCOT Real Time Adders And Reserves](https://www.gridstatus.io/datasets/ercot_real_time_adders_and_reserves) (`ercot_real_time_adders_and_reserves`)
4. [ERCOT System AS Capacity Monitor](https://www.gridstatus.io/datasets/ercot_system_as_capacity_monitor) (`ercot_system_as_capacity_monitor`)
   1. replaces [ERCOT Real Time AS Monitor](https://www.gridstatus.io/datasets/ercot_real_time_as_monitor) (`ercot_real_time_as_monitor`)
5. [ERCOT PRC](https://www.gridstatus.io/datasets/ercot_prc) (`ercot_prc`)
   1. The `prc` in this dataset is a higher frequency version of that in `ercot_system_as_capacity_monitor`
6. [ERCOT Current Conditions](https://www.gridstatus.io/datasets/ercot_current_conditions) (`ercot_current_conditions`)
   1. Captures the information from <https://www.ercot.com/gridmktinfo/dashboards/gridconditions>
7. [ERCOT Highest Price AS Offer Selected DAM](https://www.gridstatus.io/datasets/ercot_highest_price_as_offer_selected_dam) (`ercot_highest_price_as_offer_selected_dam`)
   1. Replaces [ERCOT Highest Price as Offer Selected](https://www.gridstatus.io/datasets/ercot_highest_price_as_offer_selected) (`ercot_highest_price_as_offer_selected`)
8. [ERCOT Highest Price AS Offer Selected SCED](https://www.gridstatus.io/datasets/ercot_highest_price_as_offer_selected_sced) (`ercot_highest_price_as_offer_selected_sced`)

#### Deployment Factors

1. [ERCOT AS Deployment Factors Hourly RUC](https://www.gridstatus.io/datasets/ercot_as_deployment_factors_hourly_ruc) (`ercot_as_deployment_factors_hourly_ruc`)
2. [ERCOT AS Deployment Factors Projected](https://www.gridstatus.io/datasets/ercot_as_deployment_factors_projected) (`ercot_as_deployment_factors_projected`)
3. [ERCOT AS Deployment Factors Daily RUC](https://www.gridstatus.io/datasets/ercot_as_deployment_factors_daily_ruc) (`ercot_as_deployment_factors_daily_ruc`)
4. [ERCOT AS Deployment Factors Weekly RUC](https://www.gridstatus.io/datasets/ercot_as_deployment_factors_weekly_ruc) (`ercot_as_deployment_factors_weekly_ruc`)

#### Demand Curves

1. [ERCOT AS Demand Curves](https://www.gridstatus.io/datasets/ercot_as_demand_curves) (`ercot_as_demand_curves_dam_and_sced`)
2. [ERCOT AS Demand Curves Hourly RUC](https://www.gridstatus.io/datasets/ercot_as_demand_curves_hourly_ruc) (`ercot_as_demand_curves_hourly_ruc`)
3. [ERCOT AS Demand Curves Daily RUC](https://www.gridstatus.io/datasets/ercot_as_demand_curves_daily_ruc) (`ercot_as_demand_curves_daily_ruc`)
4. [ERCOT AS Demand Curves Weekly RUC](https://www.gridstatus.io/datasets/ercot_as_demand_curves_weekly_ruc) (`ercot_as_demand_curves_weekly_ruc`)

### Retired Datasets

These datasets are preserved but no longer receive new data updates.

1. [ERCOT Real Time AS Monitor](https://www.gridstatus.io/datasets/ercot_real_time_as_monitor) (`ercot_real_time_as_monitor`) is being retired and replaced with the dataset below
   * Due to large changes in AS data post RTC+C, we've decide to biffurcate the datasets. The old dataset will stick around, but not longer receive updates.
   * The dataset id of the new dataset will be [`ercot_system_as_capacity_monitor`](https://www.gridstatus.io/datasets/ercot_system_as_capacity_monitor).&#x20;
   * If using the PRC column, we recommend migrating to [ERCOT PRC](https://www.gridstatus.io/datasets/ercot_prc) (`ercot_prc`)
2. [ERCOT Real Time Adders And Reserves](https://www.gridstatus.io/datasets/ercot_real_time_adders_and_reserves) (`ercot_real_time_adders_and_reserves`) is being retired and replaced with the dataset below
   * This dataset has been replaced by a new dataset with the id [`ercot_real_time_adders`](https://www.gridstatus.io/datasets/ercot_real_time_adders).&#x20;

### Deprecated Datasets

These datasets may still be updated but are scheduled for removal. Please migrate to new datasets as described below

1. [ERCOT AS Prices](https://www.gridstatus.io/datasets/ercot_as_prices) (`ercot_as_prices)` has been be deprecated and replaced with the dataset below&#x20;
   * This dataset has been replaced by a new dataset with the id [`ercot_mcpc_dam`](https://www.gridstatus.io/datasets/ercot_mcpc_dam)
   * The `ercot_as_prices` previously had just the DAM prices, but that was not indicated in the dataset id.&#x20;
   * Additionally, the schema of the new  dataset matches the other new AS dataset: [`ercot_mcpc_sced`](https://www.gridstatus.io/datasets/ercot_mcpc_sced) and [`ercot_mcpc_real_time_15_min`](https://www.gridstatus.io/datasets/ercot_mcpc_real_time_15_min)
2. [ERCOT AS Reports](https://www.gridstatus.io/datasets/ercot_as_reports) (`ercot_as_reports)` has been be deprecated and replaced with the dataset below&#x20;
   1. This dataset has been replaced by a new dataset with the id [`ercot_as_reports_dam`](https://www.gridstatus.io/datasets/ercot_as_reports_dam)
3. [ERCOT Highest Price as Offer Selected](https://www.gridstatus.io/datasets/ercot_highest_price_as_offer_selected) (`ercot_highest_price_as_offer_selected`) has been deprecated and replaced with [`ercot_highest_price_as_offer_selected_dam`](https://www.gridstatus.io/datasets/ercot_highest_price_as_offer_selected_dam)

### **Dataset with more information to come**

* 60 Day Disclosure datasets
  * Information about how these datasets will change hasn’t been released, but we expect significant revisions.

### Other RTC+B Datasets and Support

If there are additional datasets you’d like us to collect, please reach out to support. We’ll prioritize them based on customer requests.

If you notice issues or need assistance, please don’t hesitate to reach out.


# Welcome

### Welcome to the [Grid Status](https://www.gridstatus.io/) Changelog!

Here, you can find the latest product updates, new features, and tools to help you monitor and analyze the grid.&#x20;

To view Data Catalog updates, check out the [Dataset Changelog](https://gridstatus.notion.site/dataset-changelog). Premium datasets are available as an add-on for paid subscriptions. If you do not see a dataset you need, submit your request to <support@gridstatus.io>.&#x20;

<figure><img src="/files/wjEROfiwRj59Wnj08wWn" alt=""><figcaption></figcaption></figure>


# 10 August: Add Live Binding Constraint Heat Map

<figure><img src="/files/HRTxoV5t1Or5ZpDGWBWX" alt=""><figcaption><p>CAISO Live Page and the Constraints tab featuring the CAISO Branch Shadow Prices RTM 5 min dataset.</p></figcaption></figure>

We added a Binding Constraint Heat Map that aggregates on shadow price versus cost. This tracks constraints based on time interval. Choose the relevant dataset from the upper right drop down menu.

When viewing a single day, the data displays at an interval-level, and the value shown is the shadow price ($/MWh) for that interval. For more than one day, up to seven days, the value shown is the hourly total constraint cost ($/MW) across binding intervals. For periods greater than 7 days, the value represents the total daily cost ($/MW) of the constraint summed across all binding intervals.

When multiple contingencies bind for the same constraint in a given time period, the interval view shows the shadow price with the largest absolute value among those contingencies, and cost views sum the constraint cost across all contingencies.

Visit [Grid Status Live Pages](https://www.gridstatus.io/live) to check it out.&#x20;


# 6 August: Refresh Insights Homepage

<figure><img src="/files/Lq6xm6YDcCBBx1YzIFLi" alt=""><figcaption><p>New Insights homepage and pinned post layout.</p></figcaption></figure>

We've updated the Insights homepage. The main page features pinned posts and a list of **Latest** posts. Individual insight posts have been redesigned to share top-level information.&#x20;

You can also sign up for a weekly digest that surfaces top stories.&#x20;

To browse Grid Status Insights, visit the [Insights homepage](https://www.gridstatus.io/insights).&#x20;


# 3 August: Enhance SPP Interchange Charts

<figure><img src="/files/jk1tMXpUXm1U2wYBn5jg" alt=""><figcaption><p>Expanded menu for SPP Interchange views from the SPP Live Page and Conditions dashboard.</p></figcaption></figure>

We've updated the SPP Interchange Real Time chart to provide the following options:

* SPP West Interchange by BA: Includes sum interchange, APS, PNM, NWMT, PSCO, WALC, PACE, BHBA. This visualizes the [SPP West Interchange Real Time](https://www.gridstatus.io/datasets/spp_west_interchange_real_time) dataset.
* SPP East Interchange by BA: AECI, AMRN, BLKW, CLEC, EDDY, EES, ERCOTE, ERCOTN, LAMAR, MEC, SCSE, SOUC, SPA, TVA, RCEAST, SPC, MCWEST, SGE, ALTW, DPC, GRE, MDU, NSP, OTP. This visualizes the [SPP Interchange Real Time](https://www.gridstatus.io/datasets/spp_interchange_real_time.) dataset.
* SPP West Interchange Schedule: SWPW NAI, SWPW NSI, SWPW Future. This visualizes the [SPP West Interchange Real Time](https://www.gridstatus.io/datasets/spp_west_interchange_real_time) dataset.
* SPP West Interchange All: APS, PNM, NWMT, PSCO, WALC, PACE, BHBA,SWPW NAI, SWPW NSI, SWPW Future. This visualizes the [SPP West Interchange Real Time](https://www.gridstatus.io/datasets/spp_west_interchange_real_time) dataset.

Visit the [SPP Live Page](https://www.gridstatus.io/live/spp#spp_west) to check it out and follow our SPP Insights [here](https://www.gridstatus.io/insights/topics/spp_west) for more analysis.


# 30 July: Refresh Insight Page Layout

<figure><img src="/files/HM0aZQcGWSOBDshmPg2c" alt=""><figcaption><p>ERCOT's Leading Fuel Source insight authored by Abby Lestina on July 28, 2026.</p></figcaption></figure>

{% hint style="info" %}
A paid Grid Status subscription is required for full access to Grid Status Insights. Contact <support@gridstatus.io> if you are interested in Market Advisory calls and on-demand sessions with our Markets team.
{% endhint %}

You can now view Grid Status Insights in a new layout. The layout features an article style page and uses in-page photo formatting. At the bottom of the page, you can find a *Next Up* feed and read more related topics.

To browse Grid Status Insights, visit the [Insights Feed homepage](https://www.gridstatus.io/insights).&#x20;


# 25 July: Add Generation History Graph to Power Plant Map

<figure><img src="/files/Cv6iVhcdw2uLY9mG3KnJ" alt=""><figcaption><p>Shell Deer Park Generation History featured in the graph pop up on the Nodal Price Map.</p></figcaption></figure>

You can now view the generation history in-screen when navigating power plants in the Nodal Price Map and the Power Plant Map. Click a power plant when the power plant layer is available and view a stacked monthly bar graph of the plant's output. The stack is by fuel type and uses gross generation for the y-axis value.&#x20;

To view the dataset, you can check out [EIA Power Plant Operations](https://www.gridstatus.io/datasets/eia_power_plant_operations) dataset.

Visit the [Nodal Price Map](https://www.gridstatus.io/map) to try it out.


# 23 July: Add Hex Overlay View to Nodal Price Map

<figure><img src="/files/maC2yT5Ot4uBOBiUIuSh" alt=""><figcaption><p>Hex Display Mode applied to the Nodal Price Map.</p></figcaption></figure>

You can now choose the Hex Display Mode on the Nodal Price Map. This feature aggregates nearby nodes into hexagons colored by mean price. It is useful for spotting regional patterns when individual nodes are too dense.

Visit the [Nodal Price Map](https://www.gridstatus.io/map) to try it out.


# 17 July: Add Binding Constraints Table to Live Pages

{% hint style="info" %}
A Grid Status Labs product and is still under development. Reach out to <support@gridstatus.io> and provide us with any feedback or requests.
{% endhint %}

<figure><img src="/files/Bid1kpf4yFwuAsHgl0YZ" alt=""><figcaption><p>Expanded view for the PJM Binding Constraints table and dropdown menu for dataset selection.</p></figcaption></figure>

The binding constraint data table tracks limits that actively restrict power flows over time intervals. This table shows a subset of columns from the relevant constraint table. For complete data, query the selected dataset directly.

Reach out to <support@gridstatus.io> for access if you're interested in the Grid Status Constraint Analysis application.


# 15 July: Add CAISO Generation Outages to Live Page

<figure><img src="/files/LtO87gJF2jQW5FfAf2VE" alt=""><figcaption><p>Conditions dashboard for CAISO Live Page.</p></figcaption></figure>

Added the CAISO Generation Outages charts to the [CAISO Live Page](https://www.gridstatus.io/live/caiso). The first chart is a sum of all generator outages at any point in each interval. The Forecasted Generation Outages provides users the option to select their region or trading hub and customize the chart to the relevant view.

To view the dataset, you can check out [CAISO Aggregated Generation Outages](https://www.gridstatus.io/datasets/caiso_aggregated_generation_outages) dataset.&#x20;


# 9 July: Add MISO ACE Chart to Live Page

<figure><img src="/files/0rzr9dPwzHnZCZFvGrzJ" alt=""><figcaption><p>MISO Area Control Error (ACE) chart featured on the MISO Live Page.</p></figcaption></figure>

Added the MISO Area Control Error (ACE) chart to the [MISO Live Page](https://www.gridstatus.io/live/miso). The chart shows ACE which is calculated every 15 seconds. Negative ACE indicates that load is outpacing supply, while positive ACE indicates that supply is exceeding load.

To view the dataset, you can check out [MISO Area Control](https://www.gridstatus.io/datasets/miso_area_control_error) or select the download button to export the chart's information.&#x20;

<figure><img src="/files/3VNFLNecczw0mC1NZLUt" alt="" width="375"><figcaption><p>Custom dashboard view and component menu expanded.</p></figcaption></figure>

To use the pre-built component, navigate to a custom dashboard and view under *Prebuilt by ISOs.*


# 8 July: Add Shift Factor Exports to Application and API

{% hint style="info" %}
An enterprise subscription is required to complete API queries and export shift factor data. Reach out to <support@gridstatus.io> to learn more.
{% endhint %}

Query the Grid Status API and access the shift factor dataset. Visit our Developer documentation and learn more at [Guides](/developers/guides/best-practices).

<figure><img src="/files/AJAmK5cq3dt4qB9t37cY" alt=""><figcaption><p>Option to download shift factor data as a CSV file from the Constraint Analysis application.</p></figcaption></figure>

You can also export data from the application by selecting the download button located on charts and download a CSV file.&#x20;


# 2 July: Add Substations to Map Application

<figure><img src="/files/K85khNXFsQ7WhV1nGUZF" alt=""><figcaption><p>View of Don Marquis Substation on the Grid Infrastructure map.</p></figcaption></figure>

We've added substations to the Map Application. This map layer is tied to the transmission lines and can be toggled on or off using the legend. Double-click to zoom on that substation and the geographic area.

To try it out, visit the [Nodal Price Map](https://www.gridstatus.io/map) and turn on the Grid Infrastructure map layer.


# 25 June: Add Data Table to Map Application

<figure><img src="/files/HHtpUcIeySUFKx1411my" alt=""><figcaption><p>Data Table for Nodal Price Map</p></figcaption></figure>

We've added a Data Table to the Map Application. This is available for the Nodal Price Map, Power Plant Map, and the Grid Infrastructure Map.&#x20;

To navigate the data table, you can select between **All Rows** or **In View.** Tables support sorting by column headers.&#x20;

To try it out, visit the [Nodal Price Map](https://www.gridstatus.io/map).


# 19 June: Add API Analytics to Account Settings

<figure><img src="/files/qzNKeEaMwVIQ5MjhFers" alt=""><figcaption><p>View of subscription usage and usage breakdown.</p></figcaption></figure>

There are now additional views for API usage under your Account Settings. Users can now track:

* Breakdowns by user and organization
* Usage time frames
* Download usage data

Visit [Usage](https://www.gridstatus.io/settings/usage) to view your subscription information.


# 18 June: Block Pricing Added to Nodal Analysis

<figure><img src="/files/xbiPeHKd7Aeiqs878ZkF" alt=""><figcaption></figcaption></figure>

From the Nodal Analysis App, you are now able to access block pricing views on the node page.  Note that you can select "Block Pricing" as a tab, and specify your chosen block type in the upper right.  This provides additional quick views of pricing for your node of choice.&#x20;


# 10 June: Release Grid Status Trends

<figure><img src="/files/UnQUAu2OjDwSqEZDbowM" alt=""><figcaption><p>Grid Status Trends home page.</p></figcaption></figure>

You can now view Grid Status Trends. Using the following information, you can track historical trends against today's market conditions:

* Metric Type: Supply, Demand
* Metric: Wind, Solar, Natural Gas, Nuclear, Coal, Oil, Battery Discharge, Imports
* Period: Today, This month, This year
* ISO: Everywhere, ERCOT, CAISO, SPP, PJM, MISO, NYISO, ISONE, IESO

Visit [Grid Status Trends](https://www.gridstatus.io/trends) to try it out for yourself.


# 8 June: Add Transmission Lines to Nodal Price Map

<figure><img src="/files/3Y6EjNmoVJI2AvcXG1dO" alt=""><figcaption><p>Search results for transmissions lines and map results corresponding with the search.</p></figcaption></figure>

We've added transmission lines to the **Nodal Price Map** and the **Nodal Analysis** Details section. The line name, voltage, operator, and type will appear when you hover over a specific transmission line.&#x20;

From the Nodal Price Map, you can select to only view transmission lines based on voltage classes. With control over filters, you can locate specific transmission lines and also complete a search using the line name or owner. Clicking on a transmission line will automatically bring the line and other selected map information into focus for you to view what is in proximity of the line.&#x20;

Visit the [Nodal Price Map](https://www.gridstatus.io/map) to view Transmission Lines.


# 5 June: Block Pricing for Hubs on Live Pages

<figure><img src="/files/0DoD23r9RANUeoIOlBCU" alt=""><figcaption></figcaption></figure>

On the ISO Live Pages, you're now able to view block prices for hubs in the chosen ISO. This new feature provides valuable pricing summaries for yesterday, today, next day once available, and a Month to Date (MTD) value. You can change the location by hitting the drop down at the bottom of the Block Price display.

To view, visit [Grid Status Live](https://www.gridstatus.io/live).&#x20;


# 4 June: API Request Suggestions for Invalid Dataset IDs

<figure><img src="/files/RLHyIRT5tOr8qxqe65hm" alt=""><figcaption><p>API response suggestions for an invalid dataset ID.</p></figcaption></figure>

We've added dataset ID suggestions for when a request references a dataset ID that does not exist or is not accessible. The 3-5 suggestions improve usability and assist with next steps.


# 1 June: Refresh Account Settings Layout

<figure><img src="/files/IRke6BBhloOGrbzpuEY1" alt=""><figcaption><p>Plans &#x26; Billing page from the Account Settings.</p></figcaption></figure>

We've replaced the horizontal navigation menu with a sidebar layout. With a vertical layout, you'll see page information update to the right and relevant details per section.&#x20;

Visit [Settings](https://www.gridstatus.io/settings/billing) to edit your account settings and view usage information.&#x20;


# 22 May: Add ISONE Fuel Mix Battery Records

<figure><img src="/files/CCBmGqhYZzCIQMH0tLno" alt=""><figcaption></figcaption></figure>

We've added the following records for ISONE:

* [ISONE Maximum Battery Discharging Record](https://www.gridstatus.io/records/isone?record=Maximum%20Battery%20Discharging)
* [Maximum Battery Discharge To Total Demand Ratio Record](https://www.gridstatus.io/records/isone?record=Maximum%20Battery%20Discharge%20To%20Total%20Demand%20Ratio)\*

\*The ratio is calculated based on `isone_fuel_mix.batteries` / `isone_total_demand_5_min.total_load`


# 21 May: Refresh ERCOT 4CP Monitor

<figure><img src="/files/z5PHZU6ZkIIffhT16kta" alt=""><figcaption><p>Forecast evolution for June 1 and view from the ERCOT 4CP Monitor.</p></figcaption></figure>

We've updated the ERCOT 4CP Monitor to make it easier to navigate markets and inform your team with the latest during this summer season.&#x20;

Updates include:

* **4CP Risk Outlook**: View the 7-day risk estimates and scoring system for the peak window. The risk outlook surfaces upward and downward trends. With hourly updates, you can view the forecast evolution and see how the risk estimates are developing over time.&#x20;
* **Daily Peak Window**: The Daily Peak Window card zooms in on the peak period to show the current forecast, MTD peak, and, during the window, the Estimated CP Load. You can also flip back to any previous day for a look at demand behavior and outcomes over the peak.

*\*Note that ERCOT no longer includes battery charging load in its reported load data, so Grid Status no longer subtracts WSL to calculate an estimate of 4CP load.*&#x20;

Check out the [ERCOT 4CP Monitor](https://www.gridstatus.io/apps/ercot-4cp) and stay on top of updates by following the [Insights 4CP topic page](https://www.gridstatus.io/insights/topics/4cp).

{% hint style="info" %}
The ERCOT 4CP Monitor is free for the month of June 2026. For a paid subscription, reach out to <contact@gridstatus.io>.&#x20;
{% endhint %}


# 18 May: Sync Tooltips on Custom Dashboards

<figure><img src="/files/BuilsCEjasV8BQBnUoNs" alt=""><figcaption><p>Custom dashboard with settings menu open and "Sync Tooltips" selected.</p></figcaption></figure>

You can now sync tooltips across charts on a custom dashboard. Open the dashboard settings menu to enable tooltip syncing and hover over any chart to highlight and display data across all charts. The tool tip will then display values across multiple charts for the same time interval.&#x20;

To view, visit [Charts & Dashboards](https://www.gridstatus.io/dashboards) and select a custom dashboard.


# 16 May: Release Grid Status Chart Embedding

{% hint style="info" %}
Iframe embeds are available as add-ons for Enterprise Subscriptions. Reach out to <contact@gridstatus.io> to learn more.
{% endhint %}

<figure><img src="/files/oQwnzEYugl1EYyhkNrCm" alt=""><figcaption></figcaption></figure>

You can now embed pre-built or custom charts. Iframe embeds are a low-code way to add Grid Status data and visuals to your applications.&#x20;

View documentation to read more about [Embedding Grid Status](/developers/embedding-grid-status/embed-charts).


# 15 May: Add Supply & Demand Chart to ERCOT Live Page

<figure><img src="/files/cNlVAPdtu2m470oq4UhA" alt=""><figcaption><p>Chart view on ERCOT Live Page.</p></figcaption></figure>

Add a supply and demand chart to the ERCOT Live Page. The chart includes the following datasets and columns:

* ERCOT Capacity Committed: capacity
* ERCOT Load: load
* ERCOT Load Forecast: load\_forecast
* ERCOT Capacity Forecast: committed\_capacity
* ERCOT Capacity Forecast: available\_capacity

Visit [ERCOT Live Page](https://www.gridstatus.io/live/ercot) to view.


# 14 May: Refresh Map Navigation Panel

<figure><img src="/files/9lS3aM6fLA093PwvdPs1" alt=""><figcaption><p>Map navigation panel with layers menu expanded and Weather Radar selected.</p></figcaption></figure>

We've reorganized the map controls into a cleaner, collapsible panel. Price Nodes and Power Plants now live in dedicated sections with visibility toggles, and a Layers menu lets you quickly switch between Street and Satellite base maps and overlay Weather Radar.&#x20;

The updated layout keeps controls accessible and provides a cleaner view of the map.

To try it out, visit the [Nodal Price Map](https://www.gridstatus.io/map).


# 13 May: Release EDAM dashboard for CAISO Live Page

<figure><img src="/files/Etthg3DXWnRzWjnFW4EE" alt=""><figcaption><p>CAISO Live Page featuring the EDAM Pre-Built Dashboard.</p></figcaption></figure>

The CAISO Live page now includes a dedicated EDAM tab for monitoring the Extended Day-Ahead Market. View pricing, load, and solar and wind data from the pre-built dashboard.&#x20;

If you need help analyzing the dashboard, check our blog, [Western Markets Expansion Part 3](https://blog.gridstatus.io/the-starting-line-of-edam/), where we go over Day-Ahead clears, interchange data, GHG pricing, and more.

Check out the new [EDAM Live Page](https://www.gridstatus.io/live/caiso?date=2026-05-05#edam).


# 12 May: Add Search to Charts & Dashboards Library

<figure><img src="/files/nsr528r7ywKxguPLU72V" alt=""><figcaption><p>Search results for "PJM" Charts and Dashboards</p></figcaption></figure>

You can now search by name to quickly find any custom chart or dashboard. Filter your list and narrow the available results without scrolling or sorting through your custom analytics.&#x20;

To view, visit [Charts & Dashboards](https://www.gridstatus.io/dashboards).


# 7 May: Add CSV Downloads for Nodal Analysis Charts

<figure><img src="/files/A6caG0i61Sgkc3DNiwiJ" alt=""><figcaption><p>Download feature for the Top-Bottom Spread chart.</p></figcaption></figure>

You can now download the underlying data from any chart in Nodal Analysis, including the Top-Bottom Spread chart, as a CSV file. Get easy access to the aggregated data and analytics for your selected node.

To try it out, visit Grid Status [Nodal Analysis](https://www.gridstatus.io/nodes).




---

[Next Page](/llms-full.txt/1)

