Tariff API

Manage tariffs, tariff transitions, and tariff items — list, create, read, update, delete, and catalogue operations.

Tariff API Documentation

Overview

The Tariff API provides endpoints for managing tariffs, their successor transitions, and their pricing components (tariff items). Tariffs are associated with organizations and meter types, and can be cloned from a global read-only catalogue. Tariffs can also reference a distribution provider (DSO) and, for time-of-use tariffs, a time-of-use schedule.

Authentication

All tariff endpoints require authentication. Include a valid Bearer token in the Authorization header: Authorization: Bearer <access_token>.

Account scoping

All endpoints require an account_id UUID to scope reads and writes to a specific organization.

  • List / read / delete — pass account_id as a query parameter
  • Create / update — include account_id in the JSON request body

Response format

All endpoints return a unified envelope:

{
  "success": true,
  "message": "optional human readable message",
  "data": {},
  "count": 1,
  "error": "error text"
}

Enum reference

These enums are shared across tariffs, tariff items, and time-of-use scheduling. Individual endpoints may accept a subset of these values — see each endpoint's field reference below.

  • Meter type: ELECTRICITY | WATER | GAS | SOLAR | GENSET | HVAC | CARBON | EV
  • Tariff type: FLAT | TIME_OF_USE | BLOCK | DYNAMIC
  • Currency: ZAR | USD | EUR | GBP | AUD | CAD | JPY | CNY
  • Season: SUMMER | WINTER | TRANSITION (do not use) | ALL_YEAR
  • Tariff item type: TOU_PEAK_ENERGY | TOU_OFF_PEAK_ENERGY | TOU_STANDARD_ENERGY | IMPORT_ENERGY | EXPORTED_ENERGY | ANCILLARY_SERVICE | REACTIVE_ENERGY | NETWORK_CAPACITY | NETWORK_DEMAND | URBAN_LV_SUBSIDY | SERVICE | ADMINISTRATION | RURAL_SUBSIDY | LEGACY | GENERATION_CAPACITY | TRANSMISSION_NETWORK | WATER_CONSUMPTION | CARBON | EV_MIN | EV_SESSION_FEE | AFFORDABILITY | EXCESS_NETWORK_CAPACITY | ELECTRIFICATION_AND_RURAL_SUBSIDY
  • TOU day type: WEEKDAY | SATURDAY | SUNDAY | PUBLIC_HOLIDAY
  • TOU period: PEAK | STANDARD | OFF_PEAK

Field reference

Tariff record (selected fields):

  • id (integer)
  • name (string)
  • description (string|null)
  • account_id (uuid)
  • dso_id (integer|null) — foreign key to the energy provider
  • tou_schedule_id (integer|null) — foreign key to a time-of-use schedule, only set when tariff_type is TIME_OF_USE
  • meter_type (enum, see Enum reference)
  • tariff_type (enum, see Enum reference)
  • currency (enum, see Enum reference)
  • tax_rate (decimal)
  • is_active (boolean)
  • effective_from / effective_to (date)
  • timezone (string) — IANA timezone identifier
  • notes (string|null)
  • cloned_from (integer|null) — source tariff ID when this tariff was cloned from the catalogue

DSO object (nested on tariff reads, null when no provider is set):

  • id (integer)
  • name (string)
  • tz (string) — IANA timezone identifier (e.g. Africa/Johannesburg)

Tariff item record (selected fields):

  • id (integer)
  • tariff_id (integer)
  • item_type_code (enum, see Enum reference)
  • price (decimal)
  • season (enum, see Enum reference)

Tariff transition record:

  • id (integer)
  • predecessor_id (integer) — the current tariff being replaced
  • successor_id (integer) — the tariff that replaces it
  • effective_from (ISO 8601 timestamp) — when the successor takes over
  • notes (string)
  • created_at (ISO 8601 timestamp)
  • created_by (uuid|null)

Endpoints

Base path: /api/v1/tariffs

List Tariffs

GET /api/v1/tariffs

Query parameters:

  • account_id (uuid, required)
  • page (int, default 1)
  • limit (int, default 10, max 100)
  • query (string, optional — text search)
  • sortBy (string, default created_at)
  • sortOrder (asc | desc, default desc)
  • meter_type (enum: ELECTRICITY | GAS | WATER | CARBON | SOLAR | GENSET | EV, optional)
  • tariff_type (enum: FLAT | TIME_OF_USE | BLOCK, optional)
  • dso_id (int, optional)

Response 200 — list envelope with data array and count.

Create Tariff

POST /api/v1/tariffs

Request body (JSON):

  • account_id (uuid, required)
  • name (string, required)
  • description (string, optional)
  • timezone (string, optional)
  • notes (string, optional)
  • meter_type (enum: ELECTRICITY | GAS | WATER | CARBON | SOLAR | GENSET, optional)
  • tariff_type (enum: FLAT | TIME_OF_USE | BLOCK, optional)
  • dso_id (int, optional)
  • effective_from (date string, required)
  • effective_to (date string, required)
  • currency (enum: ZAR, optional)
  • tax_rate (positive integer, optional)
  • is_active (boolean, optional)
  • cloned_from (integer, optional)

Example:

{
  "account_id": "<account-uuid>",
  "name": "Residential Flat Rate",
  "description": "Standard residential plan",
  "meter_type": "ELECTRICITY",
  "tariff_type": "FLAT",
  "effective_from": "2026-01-01",
  "effective_to": "2026-12-31"
}

Response 201 — created tariff object in data.

Get Tariff

GET /api/v1/tariffs/:id

Query parameters:

  • account_id (uuid, required)

Returns 200 with the tariff and its nested tariff_items array and dso object.

Update Tariff

PUT /api/v1/tariffs/:id

Request body:

  • account_id (uuid, required)
  • name (string, optional)
  • description (string, optional)
  • timezone (string, optional)
  • notes (string, optional)
  • meter_type (enum: ELECTRICITY | GAS | WATER | CARBON | SOLAR | GENSET, optional)
  • tariff_type (enum: FLAT | TIME_OF_USE | BLOCK, optional)
  • dso_id (int, optional)
  • effective_from (ISO 8601 string, optional)
  • effective_to (ISO 8601 string, optional)
  • deleted_at (ISO 8601 string, optional)
  • currency (enum: USD | EUR | GBP | ZAR, optional)
  • tax_rate (positive integer, optional)
  • updated_by (uuid, optional)
  • is_active (boolean, optional)
  • cloned_from (integer, optional)

Response 200 — updated tariff object in data.

Delete Tariff

DELETE /api/v1/tariffs/:id

Query parameters:

  • account_id (uuid, required)

Response 204 — no content.

Catalogue guard: Attempts to create, update, or delete a tariff belonging to the catalogue account return 400 (Catalogue is read-only).


Tariff Transitions

Tariff transitions link the current tariff (predecessor) to the next tariff (successor). Each predecessor tariff can only have one successor transition.

When a transition is created or updated with an effective_from timestamp at or before the request time, the API immediately replaces the predecessor tariff with the successor tariff anywhere it is directly assigned to meters or building-block energy dashboard tariff fields. Future-dated transitions are recorded for scheduled tariff replacement.

Base path: /api/v1/tariffs/:id/transitions

Get Transition

GET /api/v1/tariffs/:id/transitions

Path parameter:

  • id (integer) — predecessor tariff ID

Query parameters:

  • account_id (uuid, required)

Returns 200 with the transition in data. Returns 404 if the tariff has no successor transition.

Create Transition

POST /api/v1/tariffs/:id/transitions

Path parameter:

  • id (integer) — predecessor tariff ID

Request body:

{
  "account_id": "<account-uuid>",
  "successor_id": 42,
  "effective_from": "2026-08-01T00:00:00.000Z",
  "notes": "Annual municipal tariff update"
}
  • account_id (uuid, required)
  • successor_id (integer, required) — must belong to the same organization and must differ from id
  • effective_from (ISO 8601 timestamp, required)
  • notes (string, optional)

Response 201 — created transition in data. The data.application object reports whether the transition was applied immediately and how many meter/config references were updated.

Errors: 400 invalid body or self-reference, 404 tariff not found for the account, 409 predecessor already has a successor transition.

Update Transition

PUT /api/v1/tariffs/:id/transitions

Request body:

{
  "account_id": "<account-uuid>",
  "successor_id": 43,
  "effective_from": "2026-09-01T00:00:00.000Z",
  "notes": "Revised effective date"
}
  • account_id (uuid, required)
  • successor_id (integer, optional)
  • effective_from (ISO 8601 timestamp, optional)
  • notes (string, optional)

Response 200 — updated transition in data, including data.application.

Delete Transition

DELETE /api/v1/tariffs/:id/transitions

Query parameters:

  • account_id (uuid, required)

Response 204 — no content.

Catalogue guard: Transitions cannot be managed for catalogue tariffs.


Catalogue (read-only)

The catalogue provides globally maintained, immutable tariff definitions that can be cloned into an organization's scope for customization. Catalogue tariffs and their items cannot be modified directly.

Base path: /api/v1/tariffs/catalogue

List Catalogue Tariffs

GET /api/v1/tariffs/catalogue

Query parameters:

  • page (int, default 1)
  • limit (int, default 10, max 100)
  • query (string, optional — fuzzy match against name/description)
  • sortBy (string, default created_at)
  • sortOrder (asc | desc, default desc)
  • meter_type (enum: ELECTRICITY | GAS | WATER | CARBON | SOLAR | GENSET | HVAC | EV, optional)
  • tariff_type (enum: FLAT | TIME_OF_USE | BLOCK | DYNAMIC, optional)
  • dso_id (int, optional)
  • effective_from_gte (date string, optional)
  • effective_from_lte (date string, optional)

Response 200 — data array of catalogue tariff records with count.

Get Catalogue Tariff

GET /api/v1/tariffs/catalogue/:id

Path parameter:

  • id (integer)

Returns 200 with the catalogue tariff and its nested tariff_items and dso object. Returns 404 if not found.

Clone Catalogue Tariff

POST /api/v1/tariffs/catalogue/:id/clone

Creates a new fully mutable tariff in the destination account, copying all catalogue tariff fields and items.

Path parameter:

  • id (integer) — source catalogue tariff ID

Request body:

{
  "account_id": "<destination-account-uuid>",
  "name": "Optional override name"
}
  • account_id (uuid, required) — destination organization
  • name (string, optional) — falls back to source tariff name

Response 201 — cloned tariff with tariff_items array and dso object.

Errors: 400 invalid body, 404 catalogue tariff not found.


TOU Schedule

Get TOU Schedule

GET /api/v1/tariffs/:id/schedule

Returns the Time-of-Use schedule and its linked rules for a tariff. Only applicable when tariff_type is TIME_OF_USE.

Path parameter:

  • id (integer) — tariff ID

Query parameters:

  • account_id (uuid, required)

Fallback behaviour: When the tariff has no tou_schedule_id configured, schedule ID 3 is used as the default.

Response 200 — schedule object in data:

{
  "success": true,
  "data": {
    "id": 3,
    "name": "Standard TOU Schedule",
    "dso_id": 1,
    "holiday_default": "SUNDAY",
    "is_active": true,
    "tz": "Africa/Johannesburg",
    "version": 1,
    "dso": {
      "id": 1,
      "name": "Example Municipality",
      "tz": "Africa/Johannesburg"
    },
    "tou_rules": [
      {
        "id": 1,
        "schedule_id": 3,
        "season_id": 1,
        "day_type": "WEEKDAY",
        "period": "PEAK",
        "start_minute": 420,
        "end_minute": 540
      }
    ]
  }
}

tou_schedule fields:

  • id (integer)
  • dso_id (integer)
  • name (string)
  • version (integer) — a DSO/name pair may have multiple versions
  • tz (string) — IANA timezone identifier
  • is_active (boolean)
  • holiday_default (enum, see Enum reference) — day type applied on unlisted holidays

tou_rule fields:

  • id (integer)
  • schedule_id (integer)
  • season_id (integer) — references a DSO season
  • day_type (enum, see Enum reference)
  • period (enum, see Enum reference)
  • start_minute (integer) — minutes from midnight (0–1439), must be a multiple of 30
  • end_minute (integer) — minutes from midnight (exclusive), must be a multiple of 30 and greater than start_minute

Errors:

  • 400 — tariff exists but is not TIME_OF_USE
  • 404 — tariff or TOU schedule not found

Tariff Items

List Items

GET /api/v1/tariffs/:id/items

Query parameters: page, limit, query, sortBy, sortOrder.

Returns paginated tariff_items.

Bulk Create Items

POST /api/v1/tariffs/:id/items

Body may be a single object or an array:

[
  { "price": 100.5, "item_type_code": "IMPORT_ENERGY" },
  { "price": 80.0, "item_type_code": "IMPORT_ENERGY", "season": "WINTER" }
]

Fields:

  • price (decimal, required)
  • item_type_code (enum, see Enum reference, required)
  • season (enum, see Enum reference, optional — defaults to SUMMER)

A given tariff can only have one item per (item_type_code, season) combination.

Response 201 — array of created items.

Update Item

PUT /api/v1/tariffs/:id/items/:itemId

Body fields (all optional): price, item_type_code, season.

Response 200 — updated item.

Delete Item

DELETE /api/v1/tariffs/:id/items/:itemId

Response 204 — no content.

Catalogue guard: Any attempt to modify items of a catalogue tariff returns 400 with Catalogue is read-only.


The following entities support the tariff data model. They do not currently have dedicated CRUD endpoints under /api/v1/tariffs, but they may appear as nested objects in responses (e.g. the dso object on a tariff or TOU schedule) or otherwise shape tariff behavior.

Tariff Item Types

Reference data describing each item_type_code value used on tariff items.

  • code (enum, see Enum reference) — primary key
  • displayName (string) — human readable label
  • unit (string) — unit of measure for the item (e.g. kWh, kVA, day)

Tariff Blocks

Defines tiered/block consumption pricing for a tariff item, used when a tariff's tariff_type is BLOCK. Each row represents one consumption tier for a given tariff item.

  • id (integer)
  • tariff_item_id (integer) — the tariff item this block belongs to
  • block_index (integer) — ordering of the tier (0-based)
  • upper_limit (decimal|null) — upper consumption bound for this tier; null means unbounded (the final tier)
  • unit_price_cents (integer) — price per unit for consumption within this tier, in cents

A tariff item can only have one block per block_index.

DSO (Distribution System Operator)

Represents the energy provider/utility that a tariff or TOU schedule belongs to.

  • id (integer)
  • name (string, unique)
  • tz (string) — IANA timezone identifier

DSO Season

Defines the date ranges that make up each season for a given DSO. Referenced by tou_rule.season_id.

  • id (integer)
  • dso_id (integer)
  • label (enum, see Enum reference — Season)
  • date_start / date_end (date)

DSO Public Holiday

Per-DSO public holiday calendar. A holiday may override the TOU day type that would otherwise apply on that date.

  • dso_id (integer)
  • on_date (date)
  • name (string)
  • day_type_override (enum, see Enum reference — TOU day type, optional)