BoxPower
OverviewAPI ConsoleDocumentation
Documentation

BoxPower Rates API

Integrate the BoxPower utility rates, tariff data, and cost calculation engines directly into your applications.

Authentication

Learn how to securely authenticate your requests using API keys and keep your credentials safe.

Core Endpoints

Make your first API call to the BoxPower Rates endpoints in minutes with step-by-step guides.

API Console

Explore our interactive console to test endpoints and generate snippets in Python, Node, and cURL.

Overview

The BoxPower Rates API provides programmatic access to a comprehensive database of utility rates, tariffs, and energy costs. It is designed around REST, has predictable resource-oriented URLs, accepts JSON-encoded request bodies, returns JSON-encoded responses, and uses standard HTTP response codes, authentication, and verbs.

Base URL:https://api.rates.boxpower.cloud/v1
API version1.0.0
Console version2026.09

The API version tracks the contract; the endpoints, parameters and response shapes documented here. The Console version is the interactive view component of the rate data behind it, and moves independently: a data refresh never changes a shape. The /v1 in the base URL is the path's major version, and changes only on a breaking release.

Authentication

The API uses API keys to authenticate requests. You can generate and manage your API keys in the Rate Library Hub.

Your API keys carry many privileges, so be sure to keep them secure! Do not share your secret API keys in publicly accessible areas such as GitHub, client-side code, and so forth.

HTTP Header
x-api-key: bp_live_YOUR_API_KEY

Core Endpoints

The Rate API is organized around REST. All endpoints return JSON-encoded responses and use standard HTTP status codes. Rate limits are applied per API key.

GET/utilities

List the utility companies in the dataset.

Query Parameters

ParameterTypeDescription
pageinteger1-based page number.Minimum 1. Defaults to 1.
perPageintegerItems per page. Values above 100 are rejected, not clamped.Between 1 and 100. Defaults to 25.
activeOnlystringRestrict to active utilities.One of "true" or "false".

Example Response

{
  "data": [
    {
      "id": 13,
      "utility_name": "Alaska",
      "utility_full_name": "Alaska Electric",
      "utility_logo": null,
      "subdomain": "alaska",
      "is_active": 0,
      "created_at": "2024-09-19T22:02:07.000Z",
      "updated_at": "2024-10-28T15:34:27.000Z"
    }
  ],
  "meta": { "page": 1, "perPage": 25, "total": 32, "totalPages": 2 }
}
GET/utilities/rate-names

Every distinct utility name that appears on a rate record: the values `GET /rates?utility=` matches against. Unpaginated.

Example Response

{
  "data": [
    "4-County Electric Power Association",
    "A & N Electric Cooperative - Virginia",
    "Adams-Columbia Electric Cooperative",
    "AEP - Kentucky Power Company"
  ],
  "meta": { "total": 878 }
}
GET/utilities/{id}

Retrieve one utility by its internal numeric id.

Path Parameters

ParameterTypeDescription
id*integerInternal numeric id of the utility.Minimum 1.

Example Response

{
  "data": {
    "id": 1,
    "utility_name": "PG&E",
    "utility_full_name": "Pacific Gas & Electric",
    "utility_logo": null,
    "subdomain": "pg-e",
    "is_active": 0,
    "created_at": "2024-08-23T18:58:52.000Z",
    "updated_at": "2024-10-28T15:34:15.000Z"
  }
}
GET/utilities/{id}/rates

A shortcut for one utility's rate summaries, equivalent to looking the utility up and then calling /rates?utility=<name>. Only pagination applies; the /rates filters are not accepted. It matches rates by utility name, and the names on rate records do not always match those in /utilities, so this can return an empty page. For dependable results, take a name from /utilities/rate-names and call /rates?utility= directly.

Path Parameters

ParameterTypeDescription
id*integerInternal numeric id of the utility.Minimum 1.

Query Parameters

ParameterTypeDescription
pageinteger1-based page number.Minimum 1. Defaults to 1.
perPageintegerItems per page. Values above 100 are rejected, not clamped.Between 1 and 100. Defaults to 25.

Example Response

{
  "data": [],
  "meta": { "page": 1, "perPage": 25, "total": 0, "totalPages": 1 }
}
GET/rates

Rate summaries: fourteen fields, no tariff structures. Filters combine with AND; there is no free-text search.

Query Parameters

ParameterTypeDescription
pageinteger1-based page number.Minimum 1. Defaults to 1.
perPageintegerItems per page. Values above 100 are rejected, not clamped.Between 1 and 100. Defaults to 25.
utilitystringExact utility name. See /utilities/rate-names for the accepted values.
sectorstringCustomer sector, e.g. Commercial, Residential, Industrial.
rateTypestringFilter by rate type.
approvedstringRestrict to approved rates.One of "true" or "false".

Example Response

{
  "data": [
    {
      "id": 9831,
      "name": "D-TOU-L",
      "utility": "Anaheim Public Utilities",
      "sector": "Commercial",
      "rate_type": null,
      "usenetmetering": 1,
      "fixedmonthlycharge": 743.6,
      "minmonthlycharge": null,
      "voltagecategory": null,
      "startdate": 1764547200,
      "enddate": null,
      "label": "4081620",
      "approved": 1,
      "updated_at": "2026-08-26T16:19:17.000Z"
    }
  ],
  "meta": { "page": 1, "perPage": 25, "total": 19, "totalPages": 1 }
}
GET/rates/{id}

One complete rate record, including the full tariff structures.

Path Parameters

ParameterTypeDescription
id*integerInternal numeric id of the rate.Minimum 1.

Example Response

{
  "data": {
    "id": 9831,
    "rate_family_id": 2882,
    "variant_key": "6e12d0e673d5c20236817951a4223fe1",
    "name": "D-TOU-L",
    "utility": "Anaheim Public Utilities",
    "utility_abbrev": "APU",
    "state": "CA",
    "sector": "Commercial",
    "usenetmetering": 1,
    "energyratestructure": [
      [{ "rate": 0.12123, "unit": "kWh" }],
      [{ "rate": 0.12052, "unit": "kWh" }]
    ],
    "energyweekdayschedule": [[0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0]],
    "phasewiring": "3-Phase",
    "fixedmonthlycharge": 743.6,
    "flatdemandunit": "kW",
    "demandrateunit": "kW",
    "demandratchetpercentage": [0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5],
    "startdate": 1764547200,
    "enddate": null,
    "label": "4081620",
    "type": null,
    "approved": 1,
    "attributes_json": { "Voltage Level": "11kV - 50kV" },
    "created_at": "2026-06-09T14:06:17.000Z",
    "updated_at": "2026-08-26T16:19:17.000Z"
  }
}
GET/rates/label/{label}

One complete rate record, looked up by its OpenEI/URDB label rather than our internal id.

Path Parameters

ParameterTypeDescription
label*stringThe URDB identifier carried on the rate. An empty label is a 400.

Example Response

{
  "data": {
    "id": 7518,
    "rate_family_id": 789,
    "variant_key": "d67a9ed68d760722fc89335a6533d3fb",
    "name": "GSA-1",
    "utility": "4-County Electric Power Association",
    "utility_abbrev": "4CEPA",
    "state": "MS",
    "sector": "Commercial",
    "usenetmetering": 0,
    "fixedmonthlycharge": 65.26,
    "minmonthlycharge": null,
    "phasewiring": "3-Phase",
    "energyratestructure": [
      [{"rate": 0.12123, "unit": "kWh"}],
      [{"rate": 0.12052, "unit": "kWh"}],
      [{"rate": 0.1127, "unit": "kWh"}],
      [{"rate": 0.11395, "unit": "kWh"}]
    ],
    "energyweekdayschedule": [
      [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
      [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
      [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
      [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
      [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
      [2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2],
      [2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2],
      [2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2],
      [2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2],
      [3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3],
      [3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3],
      [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
    ],
    "energyweekendschedule": [
      [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
      [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
      [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
      [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
      [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
      [2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2],
      [2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2],
      [2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2],
      [2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2],
      [3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3],
      [3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3],
      [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
    ],
    "demandratestructure": null,
    "startdate": 1743465600,
    "enddate": null,
    "label": "4071172",
    "approved": 1,
    "attributes_json": {"Service Type": "Three-Phase"},
    "created_at": "2026-06-09T14:05:42.000Z",
    "updated_at": "2026-08-26T16:18:27.000Z"
  }
}
Test these endpoints in the Console

Data shapes

Four things about the payloads catch people out. Rate structures are stored PHP-serialized upstream and decoded for you, so no special parsing is needed. But the shapes below are not the ones most JSON APIs return.

Dates are Unix epoch seconds

startdate and enddate are integers, not ISO strings. A null enddate means the rate is open-ended. By contrast created_at and updated_at are ISO date-times.

Flags are 0 or 1, not booleans

is_active, approved and usenetmetering are integers. The matching query filters, however, take the strings "true" and "false".

Rate structures are periods of tiers

The outer array is periods; each inner array holds the tiers within that period. A tier carries rate, unit, and optionally adj, sell and max.

[
  [{ "rate": 0.12123, "unit": "kWh" }],
  [{ "rate": 0.12052, "unit": "kWh" }]
]

Schedules are a 12×24 grid

Twelve months, each with twenty-four hourly values. Read it as schedule[month][hour], where month 0 is January and hour 0 is midnight, local to the utility. Each value is an index into the matching rate structure's outer array, so a schedule value of 1 means “use period 1”.

Treat every field as optional

A full rate record carries 66 fields, and most are nullable. A simple residential rate populates a handful; a large commercial tariff may populate most of the demand and coincident groups.

Errors and rate limits

Every failure shares one envelope. The details array is present on validation errors, with one entry per bad parameter.

{
  "error": {
    "code": "validation_error",
    "message": "Invalid request parameters",
    "details": [
      { "path": "perPage", "message": "Number must be less than or equal to 100" }
    ]
  }
}
CodeStatusMeaning
unauthorized401API key missing or not recognisedSend the key as an x-api-key header.
not_found404No such recordCheck the id: it is our internal numeric id, not the URDB label.
validation_error400A query parameter failed validationThe details list names each offending parameter.
rate_limited429Rate limit exceededEvery response carries RateLimit and RateLimit-Policy headers (IETF draft-7). Read them and back off before you hit this.
internal_error500Unexpected server errorOpaque by design. Quote the request_id if one is present.

Rate limits

Limits are applied per API key. Every response, not just a 429, carries RateLimit and RateLimit-Policy headers following IETF draft-7, so you can back off before you are throttled rather than after.