Power cut? Call 105 — free, 24/7, for any electricity network in the UK.

Power cut data, ready to use

Bring UK power cut information into your own apps, dashboards and services, without building a separate connection to every electricity network operator. Programmatic access to the same live incident data behind the map — cursor pagination, ISO 8601 timestamps, and errors as RFC 9457 problem+json. Base URL: https://api.outages.uk.

Get an API key

Free while the API is in early access. One active key per email address -- registering again revokes whatever was issued before and replaces it, since there's no recovery for a lost key: only its hash is ever stored.

Authentication

Send your key as a bearer token on every request: Authorization: Bearer <key>. Keys are rate-limited to 10 requests/minute; a request over that limit gets a 429 problem+json response.

How much data you get

Standard keys see a rolling 12-hour window: an incident older than that (by when it started, regardless of whether it's still ongoing) drops out of /v1/incidents and /v1/postcode-check entirely. A restored incident stays visible for 60 minutes after resolution — long enough to see that something was just fixed — then it drops out too.

Full lifecycle history beyond that window is a premium feature (GET /v1/history), not available to standard keys yet. Get in touch if continuous history is something you need.

Coverage depends on what each operator publishes, not just what they know about internally — for example Electricity North West's public dataset only includes incidents affecting 5 or more customers, so a handful of genuinely live, smaller incidents on their own website won't appear here. We surface every incident each operator's feed gives us; we can't add what isn't published there.

Endpoints

GET /v1/incidents

Current incidents across every operator, cursor-paginated, plus a freshness envelope showing which operators were stale as of that request.

ParamTypeNotes
limitinteger, optional1–100, default 50
cursorstring, optionalfrom a previous response's nextCursor
curl -H "Authorization: Bearer <key>" \
  "https://api.outages.uk/v1/incidents?limit=50"

Response (trimmed to one incident):

{
  "generatedAt": "2026-09-08T12:00:00.000Z",
  "operators": [
    { "operator": "ukpn", "name": "UK Power Networks", "stale": false,
      "lastSuccessAt": "2026-09-08T11:58:12.000Z", "lastAttemptAt": "2026-09-08T11:58:12.000Z" }
  ],
  "data": [
    {
      "id": "ukpn:INCD-105479-V",
      "operator": { "id": "ukpn", "name": "UK Power Networks",
        "attribution": "Contains data from UK Power Networks, licensed under CC BY 4.0" },
      "status": "active",
      "cause": "unplanned",
      "location": {
        "postcodeUnits": ["N1 9GU"], "postcodeSectors": ["N1 9"],
        "point": { "lon": -0.1, "lat": 51.5 },
        "pointMeaning": "affected-area-centroid", "areaName": "Islington Zone"
      },
      "customersAffected": 42,
      "estimatedRestoration": {
        "claim": { "kind": "point", "at": "2026-09-08T14:00:00.000Z" },
        "displayText": "08 Sept 14:00 - 15:00"
      },
      "fetchedAt": "2026-09-08T11:58:12.000Z"
    }
  ],
  "nextCursor": "ukpn:INCD-105480-V"
}

GET /v1/postcode-check

Whether a postcode or bare sector is currently affected.

ParamTypeNotes
postcodestring, requireda full unit (N1 9GU) or a sector (N1 9)
curl -H "Authorization: Bearer <key>" \
  "https://api.outages.uk/v1/postcode-check?postcode=N1%209GU"

GET /v1/status

Per-operator freshness on its own, uncached — the source of truth the other two endpoints' envelopes refer to.

curl -H "Authorization: Bearer <key>" \
  "https://api.outages.uk/v1/status"

GET /v1/history Premium

Same shape and parameters as GET /v1/incidents, but without the 12-hour window. Requires a premium key; a standard key gets 403 Forbidden.

ParamTypeNotes
limitinteger, optional1–100, default 50
cursorstring, optionalfrom a previous response's nextCursor
curl -H "Authorization: Bearer <premium key>" \
  "https://api.outages.uk/v1/history?limit=50"

Premium: asset monitoring & alerting Premium

Register the sites or meters you care about ("assets"), then get a webhook or email the moment an outage starts affecting one — the same feature that powers console.outages.uk's dashboard, exposed as a full CRUD API for your own integrations (an MCP server, a Zapier-style automation, your own internal tooling). Nothing here is self-serve yet: a workspace API key, not a free-tier key, is required for every route below — generate one from your console.outages.uk dashboard (Settings → API keys). A workspace key belongs to exactly one workspace, so none of these routes take a workspace id — it's implicit in the key. Not a customer yet? See what this looks like and get in touch.

Assets

Method & pathNotes
GET /v1/workspace/assetslist, plus your workspace's total allowance
GET /v1/workspace/assets/:id
POST /v1/workspace/assets400 once you're at your allowance — buy a block or free up room first
PATCH /v1/workspace/assets/:id
DELETE /v1/workspace/assets/:id
POST /v1/workspace/assets/csvbulk-create; same validation and allowance check, per row
curl -X POST -H "Authorization: Bearer <workspace key>" -H "Content-Type: application/json" \
  -d '{"name":"Head office","postcode":"N1 9GU"}' \
  "https://api.outages.uk/v1/workspace/assets"

Response:

{
  "id": "3fa2b1c0-...",
  "workspaceId": 42,
  "name": "Head office",
  "externalAssetId": null,
  "assetTypeId": null,
  "mpan": null,
  "postcodeUnit": "N1 9GU",
  "postcodeSector": "N1 9",
  "dnoOperatorId": null,
  "idno": null,
  "createdAt": "2026-09-21T09:00:00.000Z",
  "updatedAt": "2026-09-21T09:00:00.000Z"
}

postcode (a full unit or a bare sector) is the only required field beyond name. Set mpan (Meter Point Administration Number) and dnoOperatorId is derived from it automatically — it's not independently editable.

Asset types

Optional free-text grouping (e.g. "Retail site", "Warehouse") for your own reporting — not required to create an asset.

Method & pathNotes
GET /v1/workspace/asset-types
POST /v1/workspace/asset-types{ "name": "..." }
PATCH /v1/workspace/asset-types/:idrename
DELETE /v1/workspace/asset-types/:id

Alert groups

A named set of assets, so one alert rule can watch many assets at once instead of listing each individually.

Method & pathNotes
GET /v1/workspace/alert-groups
POST /v1/workspace/alert-groups{ "name": "..." }
PATCH /v1/workspace/alert-groups/:idrename
DELETE /v1/workspace/alert-groups/:id
GET /v1/workspace/alert-groups/:id/membersfull asset objects, not just ids
POST /v1/workspace/alert-groups/:id/members{ "assetId": "<uuid>" }
DELETE /v1/workspace/alert-groups/:id/members/:assetId

Alerts

A rule: watch one or more assets/groups, notify a webhook and/or a list of email addresses when a watched asset's incident status changes.

Method & pathNotes
GET /v1/workspace/alerts
GET /v1/workspace/alerts/:id
POST /v1/workspace/alerts
PATCH /v1/workspace/alerts/:idregenerates webhookSecret every time, even if the URL didn't change
DELETE /v1/workspace/alerts/:id
GET /v1/workspace/alerts/:id/deliveriesrecent delivery attempts, ?limit= up to 200
curl -X POST -H "Authorization: Bearer <workspace key>" -H "Content-Type: application/json" \
  -d '{
    "name": "Head office outages",
    "targetAssetIds": ["3fa2b1c0-..."],
    "webhookUrl": "https://example.com/hooks/outages",
    "events": ["incident.new", "incident.restored"]
  }' \
  "https://api.outages.uk/v1/workspace/alerts"

At least one of targetAssetGroupIds/targetAssetIds is required, and at least one of webhookUrl/ emailRecipients. events defaults to all three (incident.new, incident.updated, incident.restored) if omitted.

Verifying webhook deliveries

Every delivery is a signed POST with an x-outages-signature: sha256=<hex> header — an HMAC-SHA256 of the exact raw request body, keyed with the alert's own webhookSecret (shown on the alert's own GET/ POST/PATCH response; store it, it's not shown again after that). Verify against the raw bytes received, not a re-serialised copy — key order or whitespace differences would break the comparison.

const crypto = require('node:crypto');

function isValid(secret, rawBody, header) {
  const expected = crypto.createHmac('sha256', secret).update(rawBody).digest('hex');
  return header === 'sha256=' + expected;
}

Payload shape:

{
  "event": "incident.new",
  "sentAt": "2026-09-21T09:05:00.000Z",
  "alert": { "id": 7, "name": "Head office outages" },
  "asset": { "id": "3fa2b1c0-...", "name": "Head office", "externalAssetId": null },
  "incident": {
    "id": "ukpn:INCD-105479-V",
    "operator": "ukpn",
    "status": "active",
    "cause": "unplanned",
    "postcodeSector": "N1 9",
    "startedAt": "2026-09-21T08:50:00.000Z",
    "restoredAt": null,
    "customersAffected": 42
  }
}

Errors

Every error is application/problem+json: type, title, status, detail.

StatusMeaning
400a request parameter is missing or malformed — detail says which
401missing, invalid, or revoked API key
403valid key, but the endpoint needs a premium one
404no such route
429rate limit exceeded — per-key on /v1 routes, per-address on POST /v1/keys

Data rights

Most operators publish under CC BY 4.0 — attribute the originating operator wherever you display their data (each incident carries an operator.attribution string; null means that operator's licence isn't cleared for redistribution yet, and its incidents should not be shown to your own users).

Full machine-readable contract: openapi.yaml.