NAV
Python3

Introduction

WattTime technology—based on real-time grid data, cutting-edge algorithms, and machine learning—provides first-of-its-kind insight into your local electricity grid’s marginal emissions rate.

The WattTime API provides access to real-time, forecast, and historical marginal emissions data for electric grids around the world. The marginal emissions rate we provide is a Marginal Operating Emissions Rate (MOER), in units of pounds of emissions per megawatt-hour (e.g. CO2 lbs/MWh). This MOER represents the emissions rate of the electricity generator(s) which are responding to changes in load on the local grid at a certain time. For a deeper understanding of how we produce marginal emissions rates, see our methodology page.

If you’re curious about what you can do with marginal emissions data, see our ‘what we do’ page, where you can dive into the various use cases. A common example of how to use the MOER value is to quantify the avoided emissions of a decision (manual or automated) to use energy at a different time than you otherwise would have (load-shifting). To quantify the pounds of CO2 emissions avoided by load-shifting, you would multiply your time-series of shifted energy usage (counterfactual MWh less actual MWh equals shifted MWh) by the MOER timeseries (CO2 lbs/MWh), then sum the result.

You can access the API by sending standard HTTP requests to the endpoints listed below. The /data, /historical, /forecast, and /maps endpoints are only available to subscribers. However, if you don’t yet have a subscription, you can preview all of the available region-specific data by providing CAISO_NORTH as the ba for your requests. A comparison of the ANALYST and PRO data plans can be found here.

Python3 example code is provided in the right pane of this documentation which shows how to interact with the API endpoints. For an example python script that pulls everything together, please see our example code on github.

Restrictions

There is a strict limit on the rate at which you may query the API. From any user, we allow a maximum of 3,000 requests in any 5-minute rolling window (an average of 10 requests per second). If requests exceed this, an HTTP 429 error code returned.

API Status Page and User Alerts

WattTime publishes the current and historical uptime on the API Status Page. This page shows upcoming scheduled maintenance and provides updates during outages or maintenance.

Users should subscribe to alerts via the status page to be kept up to date. This page is our method of communicating updates to our users related to maintenance, outages, and announcements related to version upgrades. Follow these instructions to subscribe to alerts:

  1. Navigate to the WattTime API Status Page
  2. Click the “subscribe to updates” button in the top right corner
  3. Select your preferred means of notification (email, SMS, Slack, webhook)
  4. Enter your contact information (this will not be used for any other purpose)

Best Practices for API Usage

If using this API to control many smart devices in different locations, we suggest the following protocol. For each device location, query /ba-from-loc to determine the ba (the balancing authority serving the device). Then, query the other endpoints (e.g. /data, /forecast, etc.) with the resulting ba to receive MOER data.

Because balancing authority region boundaries are occasionally updated, it is important to re-query /ba-from-loc at least once a month to ensure devices are receiving the signal corresponding to their location.

For companies using our API to support their IOT products, we recommend that you register an API account for use by your central service/cloud that redistributes information to each device as opposed to registering an account for each end-user’s unique device.

Authentication

To start using the API, first register for an account by using the /register endpoint. Then use the /login endpoint to obtain an access token. You can then use your token to access the remainder of our endpoints. You must include your token in an authorization (bearer) header in subsequent requests to retrieve data. Your access token will expire after 30 minutes and you'll need to sign in again to obtain a new one.

Register New User

To register, use the code below. Please note that for these code examples we are using filler values for username (freddo), password (the_frog), email (freddo@frog.org), org (freds world) and you should replace each if you are copying and pasting this code.

import requests
register_url = 'https://api2.watttime.org/v2/register'
params = {'username': 'freddo',
         'password': 'the_frog',
         'email': 'freddo@frog.org',
         'org': 'freds world'}
rsp = requests.post(register_url, json=params)
print(rsp.text)

The above command returns JSON structured like this:

{
  "user": "freddo",
  "ok": "User created"
}

/register

Provide basic information to self register for an account.

HTTP Request

POST https://api2.watttime.org/v2/register

Query Parameters

Parameter Description Example Type
username (required) name of user that will be used in subsequent calls freddo string
password (required) user password. Password must be at least 8 characters, with at least 1 of each alpha, number and special characters. the_frog string
email (required) valid email address freddo@frog.org string
org organization name freds world string

Login & Obtain Token

To login and obtain an access token, use this code:

import requests
from requests.auth import HTTPBasicAuth
login_url = 'https://api2.watttime.org/v2/login'
rsp = requests.get(login_url, auth=HTTPBasicAuth('freddo', 'the_frog'))
print(rsp.json())

The above command returns your personal token, in JSON structure like this:

{
  "token": "abcdef0123456789fedcabc"
}

/login

Use HTTP basic auth to exchange username and password for an access token. Remember that you need to include this token in an authorization bearer header for all subsequent data calls. This header has the form: Authorization: Bearer <your_token>

HTTP Request

GET https://api2.watttime.org/v2/login

URL Query Parameters

Parameter Description
none uses basic authentication

Response

Attribute Description
token abcdef0123456789fedcabc

Password Reset

To reset your password, use this code:

import requests
password_url = 'https://api2.watttime.org/v2/password/?username=freddo'
rsp = requests.get(password_url)
print(rsp.json())

Sample Response:

{
  "ok": "Please check your email for the password reset link"
}

/password

Provide your username to request an email be sent to you with password reset instructions.

HTTP Request

GET https://api2.watttime.org/v2/password

URL Query Parameters

Parameter Example Type
username freddo string

Response

Attribute Description Type
"ok" Message confirming reset link has been sent string

Grid Emissions Information

Determine Grid Region

Make sure to replace the parameters username (e.g. ‘freddo’) and password (e.g. ‘the_frog’) with your registered credentials when using this code. You should not add in your token here. The code automatically generates a new token each time you run it.

import requests
from requests.auth import HTTPBasicAuth

login_url = 'https://api2.watttime.org/v2/login'
token = requests.get(login_url, auth=HTTPBasicAuth(freddo, the_frog)).json()['token']

region_url = 'https://api2.watttime.org/v2/ba-from-loc'
headers = {'Authorization': 'Bearer {}'.format(token)}
params = {'latitude': '42.372', 'longitude': '-72.519'}
rsp=requests.get(region_url, headers=headers, params=params)
print(rsp.text)

Sample Response

{
"id":169,
"abbrev":"ISONE_WCMA",
"name":"ISONE Western/Central Massachusetts"
}

/ba-from-loc

Emissions intensity varies by location, specifically the location where an energy-using device is interconnected to the grid. This endpoint, provided with latitude and longitude parameters, returns the details of the balancing authority (BA) serving that location, if known, or a Coordinates not found error if the point lies outside of known/covered BAs. For more information on what a balancing authority is, see this explanation from the EIA.

HTTP Request

GET https://api2.watttime.org/v2/ba-from-loc

URL Query Parameters

Parameter Description Example Type
latitude Latitude of device location 42.372 float
longitude Longitude of device location -72.519 float

Response

Parameter Description Example Type
abbrev Balancing authority abbreviation ISONE_WCMA string
id Unique WattTime id for the region 169 integer
name Human readable name/description for the region ISONE Western/Central Massachusetts string

List of Grid Regions

import requests
from requests.auth import HTTPBasicAuth

login_url = 'https://api2.watttime.org/v2/login'
token = requests.get(login_url, auth=HTTPBasicAuth('freddo', 'the_frog')).json()['token']

list_url = 'https://api2.watttime.org/v2/ba-access'
headers = {'Authorization': 'Bearer {}'.format(token)}
params = {'all': 'false'}
rsp=requests.get(list_url, headers=headers, params=params)
print(rsp.text)

Sample Response

{
    "ba": "CAISO_NORTH",
    "name": "California ISO Northern",
    "access": "True",
    "datatype": "MOER"
}

/ba-access

By default this endpoint delivers a list of regions to which you have access. Optionally, it can return a list of all grid regions where WattTime has data coverage. Access to this endpoint is available to all users.

HTTP Request

GET https://api2.watttime.org/v2/ba-access

URL Query Parameters

Parameter Description Example Type
all (Optional) If ‘all’: ‘true’ is specified, the entire list of regions will be returned. true Boolean

Response

Parameter Description Example Type
ba Balancing authority abbreviation CAISO_NORTH string
name Human readable name for the region California ISO Northern String
access Boolean indicator of whether the requesting user has access to the particular grid region true Boolean
datatype Type of data used to check user’s access MOER string

Real-time Emissions Index

import requests
from requests.auth import HTTPBasicAuth

login_url = 'https://api2.watttime.org/v2/login'
token = requests.get(login_url, auth=HTTPBasicAuth('freddo', 'the_frog')).json()['token']

index_url = 'https://api2.watttime.org/index'
headers = {'Authorization': 'Bearer {}'.format(token)}
params = {'ba': 'CAISO_NORTH'}
rsp=requests.get(index_url, headers=headers, params=params)
print(rsp.text)

Sample Response

{
    "freq": "300",   
    "ba": "CAISO_NORTH",
    "percent": "53",
    "moer": "850.743982",
    "point_time": "2019-01-29T14:55:00.00Z"
}

/index

Provides a real-time signal indicating the marginal carbon intensity for the local grid for the current time (updated every 5 minutes). This endpoint can return an index value, a MOER value, or both.

The index value (style: ‘percent’) is the statistical percentile value of the current MOER relative to the last one month of MOER values for the specified location (100=dirtiest, 0=cleanest). This option is available to all users.

The MOER value (style: ‘moer’) is the current MOER (e.g. CO2 lbs/MWh) for the specified location. This option is available only to users with PRO subscriptions. However, if you don’t yet have a subscription, you can preview the available data by providing CAISO_NORTH as the ba for your requests.

HTTP Request

GET https://api2.watttime.org/v2/index

URL Query Parameters

Parameter Description Example Type
ba Balancing authority abbreviation. (Optional: provide ba OR provide latitude+longitude, not all three) CAISO_NORTH string
latitude Latitude of device location 42.372 float
longitude Longitude of device location -72.519 float
style (Optional) Units in which to provide realtime marginal emissions. Choices are 'percent', 'moer' or 'all'. If you have PRO access you may use 'moer' to get the latest raw MOER value. Defaults to 'all' if not provided all string

Response

Parameter Description Example Type
freq Duration in seconds for which the data is valid from point_time 300 string
ba Balancing authority abbreviation CAISO_NORTH string
percent A percentile value between 0 (minimum MOER in the last month i.e. clean) and 100 (maximum MOER in the last month i.e. dirty) representing the relative realtime marginal emissions intensity. 53 stringified integer
moer Marginal Operating Emissions Rate (MOER) value measured in lbs/MWh. This is only available for PRO subscriptions. 850.743 stringified float
point_time ISO8601 UTC date/time format indicating when this data became valid 2019-01-29T14:55:00.00Z string

Grid Emissions Data

import requests
from requests.auth import HTTPBasicAuth

login_url = 'https://api2.watttime.org/v2/login'
token = requests.get(login_url, auth=HTTPBasicAuth('freddo', 'the_frog')).json()['token']

data_url = 'https://api2.watttime.org/v2/data'
headers = {'Authorization': 'Bearer {}'.format(token)}
params = {'ba': 'CAISO_NORTH', 
          'starttime': '2019-02-20T16:00:00-0800', 
          'endtime': '2019-02-20T16:15:00-0800'}
rsp = requests.get(data_url, headers=headers, params=params)
print(rsp.text)

Sample Response

[
{"point_time": "2019-02-21T00:15:00.000Z", "value": 844, "frequency": 300, "market": "RTM", "ba": "CAISO_NORTH", "datatype": "MOER", "version": "3.0"}, 
{"point_time": "2019-02-21T00:10:00.000Z", "value": 834, "frequency": 300, "market": "RTM", "ba": "CAISO_NORTH", "datatype": "MOER", "version": "3.0"}, 
{"point_time": "2019-02-21T00:05:00.000Z", "value": 834, "frequency": 300, "market": "RTM", "ba": "CAISO_NORTH", "datatype": "MOER", "version": "3.0"}, 
{"point_time": "2019-02-21T00:00:00.000Z", "value": 844, "frequency": 300, "market": "RTM", "ba": "CAISO_NORTH", "datatype": "MOER", "version": "3.0"}
]

/data

Obtain historical MOERS (e.g. CO2 lbs/MWh) for a specified grid region (balancing authority abbreviated code, ba) or location (latitude & longitude pair). By default, with none of the optional parameters, the response will contain the latest available value for the latest version of each available data type.

Access to this endpoint is restricted to customers with ANALYST or PRO subscriptions. However, if you don’t yet have a subscription, you can preview the available data by providing CAISO_NORTH as the ba for your requests.

HTTP Request

GET https://api2.watttime.org/v2/data/?ba=CAISO_NORTH&endtime=2019-02-20T16:15:00-0800&style=all&moerversion=3.0

URL Query Parameters

Parameter Description Example Type
ba Balancing authority abbreviation (Optional: provide ba OR provide latitude+longitude, not all three) CAISO_NORTH string
latitude Latitude of device location 42.372 float
longitude Longitude of device location -72.519 float
starttime (Optional)ISO 8601 timestamp (inclusive) - defines the first point_time of the batch. Must be provided in endtime is also provided. If omitted, the most recent data is returned. 2019-02-20T16:00:00-0800 string
endtime (Optional)ISO 8601 timestamp (inclusive) - if endtime is omitted, endtime is equal to the current time. 2019-02-20T16:15:00-0800 string
style (Optional) Style of data to provide - can be ‘all’ or ‘moer’. Defaults to ‘all’ if omitted. all string
moerversion (Optional) MOER version. Defaults to the latest version for a given region if omitted. Use this field only to request a particular version. 3.0 string

Response

Parameter Description Example Type
ba Balancing authority abbreviation CAISO_NORTH string
datatype Type of data MOER string
frequency Duration in seconds for which the data is valid from point_time 300 integer
market Disregard for MOER queries. This market type is only relevant for grid data that is not currently in use. RTM string
point_time ISO8601 UTC date/time format indicating when this data became valid 2019-01-29T14:55:00.00Z string
value Number value of the specified datatype above (e.g. Marginal Operating Emissions Rate (MOER) value measured in lbs/MWh) 909.06 float
version MOER version (Not present and not applicable for other datatypes) 3.0 string

Historical Emissions

from os import path
import requests
from requests.auth import HTTPBasicAuth

login_url = 'https://api2.watttime.org/v2/login'
token = requests.get(login_url, auth=HTTPBasicAuth('freddo', 'the_frog')).json()['token']

historical_url = 'https://api2.watttime.org/v2/historical'
headers = {'Authorization': 'Bearer {}'.format(token)}
ba = 'CAISO_NORTH'
params = {'ba': ba}
rsp = requests.get(historical_url, headers=headers, params=params)
cur_dir = path.dirname(path.realpath('__file__'))
file_path = path.join(cur_dir, '{}_historical.zip'.format(ba))
with open(file_path, 'wb') as fp:
    fp.write(rsp.content)

print('Wrote historical data for {} to {}'.format(ba, file_path))

Sample Response

Content-Type:application/zip

/historical

Obtain a zip file containing monthly .csv files with the MOER values (e.g. CO2 lbs/MWh) and timestamps for a requested region for the past two years or more.

WattTime periodically updates the algorithms used to calculate new MOERs to add new features, incorporate new data sources, or in response to changing grid dynamics. This endpoint provides you with the option to retrieve all the MOER versions published for a given region or to retrieve only the most up-to-date version.

Historical data will be updated on the 2nd day of each month at midnight UTC for the previous month.

Access to this endpoint is restricted to customers with ANALYST or PRO subscriptions. However, if you don’t yet have a subscription, you can preview the available data by providing CAISO_NORTH as the ba for your requests.

HTTP Request

GET https://api2.watttime.org/v2/historical

URL Query Parameters

Parameter Description Example Type
ba Balancing authority abbreviation CAISO_NORTH string
version (Optional) Retrieve either the latest MOER version or all MOER versions ever published for this BA.. Provide ‘latest’ for the latest version or ‘all’ for all versions. Defaults to ‘latest’ if omitted. all string

Response

Description Type
A binary zip file payload containing monthly .csv files with MOERs for the specified balancing authority for the past two years. Save the body to disk and unzip it. Binary Data Zip File

Emissions Forecast

import requests
from requests.auth import HTTPBasicAuth

login_url = 'https://api2.watttime.org/v2/login'
token = requests.get(login_url, auth=HTTPBasicAuth('freddo', 'the_frog')).json()['token']

forecast_url = 'https://api2.watttime.org/v2/forecast'
headers = {'Authorization': 'Bearer {}'.format(token)}
params = {'ba': 'CAISO_NORTH', 
          'starttime': '2021-08-05T09:00:00-0400', 
          'endtime': '2021-08-05T09:05:00-0400'}
rsp = requests.get(forecast_url, headers=headers, params=params)
print(rsp.text)

Sample Response

[
  {
    "generated_at": "2021-08-05T09:05:00+00:00", 
    "forecast": 
      [
        {
          "point_time": "2021-08-05T09:10:00+00:00",
          "ba": "CAISO_NORTH",
          "value": 887.0946245162808,
          "version": "3.0-1.0.0"
        },
        {
          "point_time": "2021-08-05T09:15:00+00:00",
          "ba": "CAISO_NORTH",
          "value": 887.2882214363948,
          "version": "3.0-1.0.0"},

         ...<24 hours worth of datapoints>...
      ]
  }
]

/forecast

Obtain a forecast of the MOERs (e.g. CO2 lbs/MWh) for a specified region. Omitting the starttime and endtime parameters will return the most recently generated forecast. Use the starttime and endtime parameters to obtain historical forecast data.

Note that starttime and endtime define the time when a forecast was generated. Every five minutes, WattTime generates a new forecast which is 24 hours in duration (or 72 hours for the extended forecast). So, if you make a request to the /forecast endpoint with starttime of Jan 1, 1:00 and endtime of Jan 1, 1:05, you will receive a set of forecast values (with 5-minute frequency) generated at 1:00 and 1:05, on January 1.

Access to this endpoint is restricted to customers with PRO subscriptions. However, if you don’t yet have a subscription, you can preview the available data by providing CAISO_NORTH as the ba for your requests.

HTTP Request

GET https://api2.watttime.org/v2/forecast

URL Query Parameters

Parameter Description Example Type
ba Balancing authority abbreviation CAISO_NORTH string
starttime (Optional) ISO 8601 timestamp (inclusive) - Omit to obtain the real-time forecast. If included, those forecasts generated between start and endtime are returned. 2021-08-05T09:00:00-0400 string
endtime (Optional) ISO 8601 timestamp (inclusive)- Omit to obtain the real-time forecast. If included, those forecasts generated between start and endtime are returned. 2021-08-05T09:05:00-0400 string
extended_forecast (Optional) Will provide a 72-hour forecast true Boolean

Response

Attribute Description Example Type
generated_at ISO 8601 timestamp indicating when the forecast was generated 2021-08-05T09:05:00+00:00 string
forecast List of forecasts - see description below object

The value of the forecast key is a list of dictionaries containing the following keys:

Key Description Example Type
ba Balancing authority abbreviation CAISO_NORTH string
point_time ISO8601 UTC date/time format indicating when this data became valid 2021-08-05T09:10:00+00:00 string
value Forecast value for the MOER measured in lbs/MWh. 887.0946245162808 float
version MOER forecast version 3.0-1.0.0 string

Grid Region Map Geometry

import requests
from requests.auth import HTTPBasicAuth
from os import path

login_url = 'https://api2.watttime.org/v2/login'
token = requests.get(login_url, auth=HTTPBasicAuth('freddo', 'the_frog')).json()['token']

maps_url = 'https://api2.watttime.org/v2/maps'
headers = {'Authorization': 'Bearer {}'.format(token)}
rsp=requests.get(maps_url, headers=headers)

cur_dir = path.dirname(path.realpath('__file__'))
file_path = path.join(cur_dir, 'wt_map.geojson')
with open(file_path, 'wb') as fp:
    fp.write(rsp.content)

Sample Response

{
    "type": "FeatureCollection", 
    "features": [
        {
            "type": "Feature", 
            "properties": {
                "abbrev": "AECI", 
                "name": "Associated Electric Coop Inc"
            }, 
            "geometry": {
                "type": "MultiPolygon", 
                "coordinates": [
                    [
                        [
                            [-92.8982, 38.8797],
                            [-92.8850, 38.8585],
                            …<all coordinates for the polygon>...
                        ]
                    ]
                ]
            }
        }
        …<all grid regions>...
    ],
    "meta": {
    "last_updated": "2022-02-17T00:57:00+00:00"
    }
}

/maps

The /maps endpoint provides a geojson of the grid region boundary for all regions that WattTime covers globally. Check when the geojson was last updated using the ‘last_updated’ value in the “meta” object of the geojson. Access to this endpoint is restricted to customers with ANALYST or PRO subscriptions.

HTTP Request

GET https://api2.watttime.org/v2/maps

URL Query Parameters

None.

Response

A geojson response, that is a Feature Collection with properties that describe each BA, and multipolygon geometry made up of coordinates which define the boundary for each BA. The “meta” object contains the date-time that the geojson was last updated.

Technical Support

For technical questions related to this API and real-time emissions data, please contact support@WattTime.org

If you are experiencing an outage, please check the WattTime API Status Page to get the status of known outages, and if none are shown, please proceed to contact support@WattTime.org