Live outage status, refreshed about every 10 minutes.
GET/api/v1/live/summary
National and per-state live totals
National live totals, coverage split and states ranked by customers out. Suitable for polling every 5 minutes.
No parameters.
200: application/json500: Unexpected server error. `request_id` matches the X-Request-Id header.
Response fields (32)
| Field | Type | Description |
|---|
| data | object | |
| data.national | object | |
| data.national.customers_out | integer | National customers out (county-level + not localized). |
| data.national.incident_count | integer | Active incidents. |
| data.national.county_count | integer | Counties with customers out. |
| data.national.state_count | integer | States with live data. |
| data.national.unmapped_out | integer | Customers out known only at utility/state level. |
| data.national.updated_at | string | null | Time of the latest live poll. |
| data.national.as_of | string | null | Oldest region's data time; older than updated_at means some region is carried forward. |
| data.national.stale | boolean | True when any region's data is being carried forward. |
| data.national.stale_out | integer | Customers out whose source is being carried forward (stale). |
| data.coverage | object | |
| data.coverage.sources | integer | Configured live sources reporting this poll. |
| data.coverage.sources_ok | integer | Sources that fetched successfully this poll. |
| data.coverage.customers_out | integer | National total. |
| data.coverage.county_level_out | integer | Customers out localized to a county. |
| data.coverage.not_localized_out | integer | Customers out known only at utility/state level. |
| data.coverage.tracked_customers | integer | Measured floor of customers under live watch. |
| data.states | array | States ranked by customers out. |
| data.states[].state_fips | string | 2-digit state FIPS. |
| data.states[].name | string | State name. |
| data.states[].abbr | string | USPS abbreviation. |
| data.states[].slug | string | URL slug. |
| data.states[].url | string | Relative MassOutage state page URL. |
| data.states[].customers_out | integer | Customers out in the state. |
| data.states[].county_count | integer | Counties with customers out. |
| data.states[].unmapped_out | integer | Customers out not placed on a county. |
| meta | object | Dataset-level provenance. Omitted when there is nothing to report. |
| meta.sources | array | Datasets this response draws on, for citation. |
| meta.sources[].name | string | Upstream dataset name. |
| meta.sources[].url | string | Resolvable URL of the upstream dataset. |
| meta.last_modified | string | null | When the underlying data last changed (live poll time on live endpoints). |
Example response (illustrative values)
{
"data": {
"national": {
"customers_out": 184203,
"incident_count": 9412,
"county_count": 611,
"state_count": 49,
"unmapped_out": 12050,
"updated_at": "2026-09-14T13:50:00.000Z",
"as_of": "2026-09-14T13:50:00.000Z",
"stale": false,
"stale_out": 0
},
"coverage": {
"sources": 64,
"sources_ok": 62,
"customers_out": 184203,
"county_level_out": 172153,
"not_localized_out": 12050,
"tracked_customers": 98000000
},
"states": [
{
"state_fips": "34",
"name": "New Jersey",
"abbr": "NJ",
"slug": "new-jersey",
"customers_out": 5210,
"county_count": 12,
"unmapped_out": 0,
"url": "/new-jersey"
}
]
},
"meta": {
"sources": [
{
"name": "ODIN (Outage Data Initiative Nationwide)",
"url": "https://odin.ornl.gov/"
}
],
"last_modified": "2026-09-14T13:50:00.000Z"
}
}
GET/api/v1/live/map
Compact severity map of every county and state out
Keyed arrays for choropleths: `[customers_out, pct_out, level, band, magnitude]`. `band` is the 0-5 share-of-customers ramp the map colours by (1/3/10/25/50%), or -1 where no denominator can be trusted; `magnitude` is a 0-5 headcount ramp. `level` is the pre-2026-09 blend, superseded by `band`; its formula is unchanged, though it moves where a clamped percentage was corrected.
No parameters.
200: application/json500: Unexpected server error. `request_id` matches the X-Request-Id header.
Response fields (4)
| Field | Type | Description |
|---|
| data | object | |
| data.generated_at | string | When this response was generated. |
| data.counties | object | County FIPS → `[customers_out, pct_out, level, band, magnitude]`. `band` is the 0-5 share-of-customers ramp the map colours by (1/3/10/25/50%), or -1 where no denominator can be trusted; `magnitude` is a 0-5 headcount ramp. `level` is the pre-2026-09 blend, superseded by `band`; its formula is unchanged, though it moves where a clamped percentage was corrected. Only counties with customers out appear. |
| data.states | object | State FIPS → `[customers_out, pct_out, level, band, magnitude]`. `band` is the 0-5 share-of-customers ramp the map colours by (1/3/10/25/50%), or -1 where no denominator can be trusted; `magnitude` is a 0-5 headcount ramp. `level` is the pre-2026-09 blend, superseded by `band`; its formula is unchanged, though it moves where a clamped percentage was corrected. |
Example response (illustrative values)
{
"data": {
"generated_at": "2026-09-14T13:50:00.000Z",
"counties": {
"34025": [
1840,
0.53,
2
]
},
"states": {
"34": [
5210,
0.13,
2
]
}
}
}
GET/api/v1/live/top
Ranked live leaders
Top 8 states (with top live cause), counties and providers by customers out.
No parameters.
200: application/json500: Unexpected server error. `request_id` matches the X-Request-Id header.
Response fields (21)
| Field | Type | Description |
|---|
| data | object | |
| data.states | array | |
| data.states[].state_fips | string | State FIPS. |
| data.states[].name | string | Name. |
| data.states[].abbr | string | Abbreviation. |
| data.states[].slug | string | Slug. |
| data.states[].customers_out | integer | Customers out. |
| data.states[].county_count | integer | Counties out. |
| data.states[].top_cause | string | null | Leading live cause label. |
| data.counties | array | |
| data.counties[].fips | string | County FIPS. |
| data.counties[].name | string | Name. |
| data.counties[].slug | string | Slug. |
| data.counties[].state_slug | string | State slug. |
| data.counties[].state_abbr | string | State abbreviation. |
| data.counties[].customers_out | integer | Customers out. |
| data.providers | array | |
| data.providers[].eia_id | string | null | EIA utility id. |
| data.providers[].name | string | Name. |
| data.providers[].slug | string | Slug. |
| data.providers[].customers_out | integer | Customers out. |
GET/api/v1/live/timeline
State severity timeline
State-level 0-5 severity resampled to 48 evenly spaced frames over the window.
| Parameter | In | Type | Description |
|---|
| hours | query | number, default 24 | Window length in hours (clamped 1-48). |
200: application/json500: Unexpected server error. `request_id` matches the X-Request-Id header.
Response fields (5)
| Field | Type | Description |
|---|
| data | object | |
| data.hours | number | Applied window. |
| data.frames | array | |
| data.frames[].t | string | Frame time. |
| data.frames[].states | object | State FIPS → level 0-5 (absent = 0). |
GET/api/v1/live/sources
Feed health and coverage (status endpoint)
How the live feeds did on their last poll in aggregate, the county-level vs not-localized split, and connector coverage of US customers. Use it as the status endpoint: check `feeds.down` and `coverage.sources_ok` before trusting a number. Per-feed rows are not published; which utility we read at what resolution is not part of the contract.
No parameters.
200: application/json500: Unexpected server error. `request_id` matches the X-Request-Id header.
Response fields (27)
| Field | Type | Description |
|---|
| data | object | |
| data.coverage | object | |
| data.coverage.sources | integer | Configured live sources reporting this poll. |
| data.coverage.sources_ok | integer | Sources that fetched successfully this poll. |
| data.coverage.customers_out | integer | National total. |
| data.coverage.county_level_out | integer | Customers out localized to a county. |
| data.coverage.not_localized_out | integer | Customers out known only at utility/state level. |
| data.coverage.tracked_customers | integer | Measured floor of customers under live watch. |
| data.feeds | object | |
| data.feeds.total | integer | Live feeds configured. |
| data.feeds.live | integer | Feeds that answered on the last poll and are within their freshness window. |
| data.feeds.stale | integer | Feeds serving carried-forward last-good data. |
| data.feeds.down | integer | Feeds that failed with no recent data (their areas show a gap). |
| data.feeds.customers_out_before_dedupe | integer | Customers out summed across feeds, before overlapping feeds are merged. Higher than the national total. |
| data.feeds.oldest_last_ok_ts | string | null | Oldest successful fetch across all feeds. |
| data.connector_coverage | object | |
| data.connector_coverage.total_customers | integer | Customers on the wires of every utility with an EIA-861 service territory, counted once each (bundled + delivery). Retail-only suppliers are excluded; see Denominator. |
| data.connector_coverage.county_customers | integer | Customers of utilities reported by county every poll (0 out is a real all-clear). |
| data.connector_coverage.utility_customers | integer | Customers of utilities reported as a utility total every poll, not by county. |
| data.connector_coverage.outage_only_customers | integer | Customers of utilities that appear in feeds only while they have outages. |
| data.connector_coverage.blind_customers | integer | Customers of utilities with no live feed. |
| data.connector_coverage.eia_year | integer | null | EIA-861 year of the customer counts. |
| data.denominator | object | |
| data.denominator.wires_customers | integer | Customers on the wires of a utility with an EIA-861 service territory, the coverage denominator. |
| data.denominator.delivery_customers | integer | Of those, the ones buying energy from a competitive supplier. Their wires utility restores their outage, so they are counted there, once. |
| data.denominator.supplier_duplicates | integer | Customers retail suppliers file for themselves, already counted on their wires utility. Excluded; reported so the exclusion is visible. |
| data.denominator.eia_year | integer | null | EIA-861 year of the customer counts. |
Example response (illustrative values)
{
"data": {
"coverage": {
"sources": 64,
"sources_ok": 62,
"customers_out": 184203,
"county_level_out": 172153,
"not_localized_out": 12050,
"tracked_customers": 98000000
},
"feeds": {
"total": 64,
"live": 62,
"stale": 1,
"down": 1,
"customers_out_before_dedupe": 196430,
"oldest_last_ok_ts": "2026-09-14T13:50:00.000Z"
},
"connector_coverage": {
"total_customers": 162000000,
"county_customers": 70000000,
"utility_customers": 20000000,
"outage_only_customers": 50000000,
"blind_customers": 22000000,
"eia_year": 2024
},
"denominator": {
"wires_customers": 162000000,
"delivery_customers": 30000000,
"supplier_duplicates": 29000000,
"eia_year": 2024
}
}
}
GET/api/v1/live/counties/{fips}
Live status for one county
Customers out, incidents, per-utility breakdown with ETRs, freshness and momentum. Returns zeros (not 404) when nothing is out. `?format=csv` downloads the per-utility breakdown.
| Parameter | In | Type | Description |
|---|
| fips* | path | string | 5-digit county FIPS code (state + county), e.g. 34025 for Monmouth County, NJ. |
| format | query | json | csv | Response format; csv returns the per-utility rows. |
200: application/json, text/csv500: Unexpected server error. `request_id` matches the X-Request-Id header.
Response fields (22)
| Field | Type | Description |
|---|
| data | object | |
| data.fips | string | 5-digit county FIPS. |
| data.customers_out | integer | Customers without power in the county right now (all live sources). |
| data.customers_tracked | integer | null | Customers served by sources that publish a denominator. |
| data.pct | number | null | customers_out / customers_tracked × 100, when a denominator exists. |
| data.incident_count | integer | Active outage incidents. |
| data.utilities | array | Per-utility breakdown of customers out. |
| data.utilities[].id | string | Utility identifier as reported by the live feed. |
| data.utilities[].name | string | Utility name. |
| data.utilities[].customers_out | integer | Customers out for this utility in the county. |
| data.utilities[].etr | string | null | Utility's estimated time of restoration (ISO 8601), the utility's estimate; it changes. |
| data.worst_etr | string | null | Latest utility ETR among active outages (ISO 8601). |
| data.updated_at | string | null | Time of the poll that produced this rollup. Null when nothing is out. |
| data.as_of | string | null | Oldest contributing source's fetch time. Older than updated_at means data is carried forward (stale). |
| data.trend | object | null | Outage momentum; null when nothing is out. |
| data.trend.direction | string enum | Momentum of the current outage. (rising, steady, improving) |
| data.trend.duration_min | integer | Minutes the current contiguous outage run has lasted. |
| data.trend.peak_out | integer | Peak customers out during the current run. |
| data.trend.series | array | Recent samples of the current run, oldest to newest. |
| data.trend.span_min | integer | Minutes covered by `series`. |
| data.trend.normalcy | string enum | How this outage compares with the county's history. (routine, elevated, major) |
| data.trend.vs_record_pct | number | null | Current customers out as % of this county's worst episode on record. |
Example response (illustrative values)
{
"data": {
"fips": "34025",
"customers_out": 1840,
"customers_tracked": 347000,
"pct": 0.53,
"incident_count": 27,
"utilities": [
{
"id": "9726",
"name": "JCP&L",
"customers_out": 1620,
"etr": "2026-09-14T18:00:00.000Z"
}
],
"worst_etr": "2026-09-14T18:00:00.000Z",
"updated_at": "2026-09-14T13:50:00.000Z",
"as_of": "2026-09-14T13:50:00.000Z",
"trend": {
"direction": "improving",
"duration_min": 140,
"peak_out": 3100,
"series": [
3100,
2800,
2200,
1840
],
"span_min": 30,
"normalcy": "elevated",
"vs_record_pct": 4.6
}
}
}
GET/api/v1/live/counties/{fips}/areas
Live municipalities/townships in a county
Every municipality each utility reports in the county, most affected first, with masked ("<N") outages and ETRs. Only feeds that report areas appear (e.g. NJ PSE&G and JCP&L).
| Parameter | In | Type | Description |
|---|
| fips* | path | string | 5-digit county FIPS code (state + county), e.g. 34025 for Monmouth County, NJ. |
| format | query | json | csv | geojson | Response format. geojson emits bbox polygons. |
| utility | query | string | Only rows for this utility: an exact `utility_key` or a case-insensitive substring of the utility name (e.g. `jcp`, `pse&g`). |
| active | query | boolean, default false | `true` keeps only areas with customers_out > 0 or masked_outages > 0. |
| min_customers | query | number | Only areas with at least this many customers out. Negative or non-numeric values are ignored. |
200: application/json, text/csv, application/geo+json400: Invalid FIPS or format.500: Unexpected server error. `request_id` matches the X-Request-Id header.
Response fields (17)
| Field | Type | Description |
|---|
| data | array | |
| data[].utility_key | string | Utility key (use with ?utility=). |
| data[].utility_name | string | Utility name. |
| data[].area_type | string | Area type as the utility reports it (e.g. Township, Borough, Municipality). |
| data[].name | string | Municipality/township name as the utility reports it. |
| data[].customers_served | integer | null | Customers the utility serves in this area. |
| data[].customers_out | integer | Customers out in this area. 0 may still hide masked outages. |
| data[].masked_outages | integer | Outages the utility reports as "<N" (count hidden for privacy). Unknown size, not zero. |
| data[].incident_count | integer | null | Incidents in this area. |
| data[].pct_out | number | null | customers_out / customers_served × 100. |
| data[].etr | string | null | Utility's estimated restoration for the area (ISO 8601). |
| data[].bbox | array | null | [minLon, minLat, maxLon, maxLat]. |
| data[].as_of | string | When the utility's feed was fetched. Rows older than 1 hour are excluded. |
| as_of | string | null | Latest feed time across the county's areas (before filters). |
| meta | object | Notice and echo of applied filters on county detail endpoints. |
| meta.notice | string | Terms of use for the data; same text as the X-Data-Notice header. |
| meta.filters | object | The filters that were applied (null/false when not set). |
Example response (illustrative values)
{
"data": [
{
"utility_key": "9726",
"utility_name": "JCP&L",
"area_type": "Borough",
"name": "BRIELLE BOROUGH",
"customers_served": 2678,
"customers_out": 412,
"masked_outages": 0,
"incident_count": 3,
"pct_out": 15.38,
"etr": "2026-09-14T18:00:00.000Z",
"bbox": [
-74.08,
40.09,
-74.04,
40.12
],
"as_of": "2026-09-14T13:50:00.000Z"
}
],
"as_of": "2026-09-14T13:50:00.000Z",
"meta": {
"notice": "Unofficial aggregate of public utility and government data; confirm with the utility or your OEM before acting. Emergencies: call 911.",
"filters": {
"utility": "jcp",
"active": true,
"min_customers": null
}
}
}
GET/api/v1/live/counties/{fips}/incidents
Live outage incidents in a county
Individual outages with location, customers out, utility ETR, crew status and cause.
| Parameter | In | Type | Description |
|---|
| fips* | path | string | 5-digit county FIPS code (state + county), e.g. 34025 for Monmouth County, NJ. |
| format | query | json | csv | geojson | Response format. geojson emits points. |
| utility | query | string | Only rows for this utility: an exact `utility_key` or a case-insensitive substring of the utility name (e.g. `jcp`, `pse&g`). |
| min_customers | query | number | Only incidents (unknown counts count as 0) with at least this many customers out. Negative or non-numeric values are ignored. |
200: application/json, text/csv, application/geo+json400: Invalid FIPS or format.500: Unexpected server error. `request_id` matches the X-Request-Id header.
Response fields (16)
| Field | Type | Description |
|---|
| data | array | |
| data[].utility_key | string | Utility key. |
| data[].utility_name | string | Utility name. |
| data[].lat | number | Latitude of the outage marker (utility-provided, often approximate). |
| data[].lon | number | Longitude. |
| data[].customers_out | integer | null | Customers out; null when the utility masks the count. |
| data[].customers_below | integer | null | Upper bound when the utility reports "<N". |
| data[].etr | string | null | Utility's estimated time of restoration (ISO 8601). |
| data[].crew_status | string | null | Crew status text as the utility reports it. |
| data[].cause | string | null | Cause text as the utility reports it. |
| data[].started_at | string | null | When the outage started. |
| data[].as_of | string | When the utility's feed was fetched. |
| as_of | string | null | Latest feed time across the county's incidents (before filters). |
| meta | object | Notice and echo of applied filters on county detail endpoints. |
| meta.notice | string | Terms of use for the data; same text as the X-Data-Notice header. |
| meta.filters | object | The filters that were applied (null/false when not set). |
Example response (illustrative values)
{
"data": [
{
"utility_key": "9726",
"utility_name": "JCP&L",
"lat": 40.108,
"lon": -74.057,
"customers_out": 212,
"customers_below": null,
"etr": "2026-09-14T18:00:00.000Z",
"crew_status": "Crew assigned",
"cause": "Tree contact",
"started_at": "2026-09-14T11:32:00.000Z",
"as_of": "2026-09-14T13:50:00.000Z"
}
],
"as_of": "2026-09-14T13:50:00.000Z",
"meta": {
"notice": "Unofficial aggregate of public utility and government data; confirm with the utility or your OEM before acting. Emergencies: call 911.",
"filters": {
"utility": null,
"min_customers": 100
}
}
}
GET/api/v1/live/counties/{fips}/alerts
Threshold alert status for a county
Evaluates your thresholds for the county, each utility (with the 10% major-event line) and each municipality. Utilities without a live feed are listed with `visible: false` and must not be treated as clear.
| Parameter | In | Type | Description |
|---|
| fips* | path | string | 5-digit county FIPS code (state + county), e.g. 34025 for Monmouth County, NJ. |
| min_customers | query | number | Customers-out threshold. |
| min_pct | query | number | Percent-out threshold (0-100). When both are set, both must be crossed. |
| utility | query | string | Only rows for this utility: an exact `utility_key` or a case-insensitive substring of the utility name (e.g. `jcp`, `pse&g`). Narrows utilities and areas; the county figure stays county-wide. |
200: application/json400: Invalid FIPS.500: Unexpected server error. `request_id` matches the X-Request-Id header.
Response fields (31)
| Field | Type | Description |
|---|
| data | object | |
| data.fips | string | 5-digit county FIPS. |
| data.thresholds | object | |
| data.thresholds.min_customers | number | null | Applied min_customers. |
| data.thresholds.min_pct | number | null | Applied min_pct. |
| data.thresholds.major_event_pct | number | Major-event percentage line (10). |
| data.county | object | |
| data.county.customers_out | integer | County customers out (county-wide, not narrowed by ?utility). |
| data.county.pct_out | number | null | Percent of county customers out. |
| data.county.above_threshold | boolean | Crosses every threshold that was set; false when none is set. |
| data.utilities | array | |
| data.utilities[].utility_key | string | Utility key. |
| data.utilities[].name | string | Utility name. |
| data.utilities[].connector_status | string enum | How MassOutage sees this utility: county = reported by county every poll (0 out is a real all-clear); utility = total only; outage_only = appears only while it has outages; none = no feed. (county, utility, outage_only, none) |
| data.utilities[].customers_out | integer | null | Customers out in the county; null when not reported. |
| data.utilities[].customers_served | integer | null | Customers served in the county. |
| data.utilities[].pct_out | number | null | Percent of the utility's county customers out. |
| data.utilities[].above_threshold | boolean | Crosses every threshold that was set. |
| data.utilities[].major_event | boolean | At least 10% of the utility's county customers out (N.J.A.C. 14:5-8.9 line). |
| data.utilities[].visible | boolean | True only for connector_status county or utility. A non-visible utility can never be reported as clear. |
| data.areas_above_threshold | array | Municipalities crossing the thresholds, largest first (area rows also carry the other LiveArea fields). |
| data.areas_above_threshold[].utility_key | string | Utility key. |
| data.areas_above_threshold[].utility_name | string | Utility name. |
| data.areas_above_threshold[].name | string | Municipality. |
| data.areas_above_threshold[].customers_out | integer | Customers out. |
| data.areas_above_threshold[].customers_served | integer | null | Customers served. |
| data.areas_above_threshold[].pct_out | number | null | Percent out. |
| data.as_of | string | null | County live data time. |
| meta | object | Notice and echo of applied filters on county detail endpoints. |
| meta.notice | string | Terms of use for the data; same text as the X-Data-Notice header. |
| meta.filters | object | The filters that were applied (null/false when not set). |
Example response (illustrative values)
{
"data": {
"fips": "34025",
"thresholds": {
"min_customers": 1000,
"min_pct": null,
"major_event_pct": 10
},
"county": {
"customers_out": 1840,
"pct_out": 0.53,
"above_threshold": true
},
"utilities": [
{
"utility_key": "9726",
"name": "Jersey Central Power & Lt Co",
"connector_status": "county",
"customers_out": 1620,
"customers_served": 297055,
"pct_out": 0.55,
"above_threshold": true,
"major_event": false,
"visible": true
},
{
"utility_key": "15477",
"name": "Public Service Elec & Gas Co",
"connector_status": "county",
"customers_out": 220,
"customers_served": 1565,
"pct_out": 14.06,
"above_threshold": false,
"major_event": true,
"visible": true
}
],
"areas_above_threshold": [],
"as_of": "2026-09-14T13:50:00.000Z"
},
"meta": {
"notice": "Unofficial aggregate of public utility and government data; confirm with the utility or your OEM before acting. Emergencies: call 911.",
"filters": {
"utility": null,
"min_customers": 1000,
"min_pct": null
}
}
}