Download OpenAPI specification:
The HEAT Cloud Public API provides programmatic access to hybrid energy sites managed by the H.E.A.T. Energy Gateway. It is a REST API authenticated with an API key, which you can obtain on the H.E.A.T. Cloud API Settings page.
Once authenticated, callers can:
upperLimitkW, lowerLimitkW(set grid import/export limits), activePowerkW (set grid or BESS active power setpoint), optimalSocPcnt (set BESS optimal state of charge), solarCurtailmentPcnt.A /health endpoint is also available for liveness/readiness probing and does not require authentication.
The API is currently at version 0.1.0. Until version 1.0 is released, we do not guarantee backward compatibility — breaking changes may occur between releases.
The API version is part of the URL path:
/api/v0/public/sites
/api/v1/public/sites
We do not create a new version for every change. A new version is only introduced when a change would break existing clients.
The following changes may happen without a version bump. Your integration should be written to handle them gracefully:
The following changes will always result in a new version:
The API uses API key authentication. Every request must include an API key in the Authorization header.
API key (from Heat Cloud website)
│
▼
All API requests (Authorization: Bearer agk_<id>.ags_<secret>)
API keys are managed in the Heat Cloud website under your account settings. Each key is associated with an access group that determines which sites the key can see.
When a key is created you receive two strings — an API key ID and an API key secret. Store the secret securely — it is not shown again after creation.
Pass the full API key as a Bearer token on every request:
Authorization: Bearer agk_<id>.ags_<secret>
The /health endpoint does not require authentication.
| Constraint | Details |
|---|---|
| Keys per access group | Maximum 20 active keys (keys that are neither revoked nor expired). |
| Name uniqueness | Key names must be unique within an access group. |
| Expiry | Optional. A key can be set to expire at a specific date/time or have no expiry. Expired keys are rejected. |
| Revocation | Keys can be revoked at any time from the Heat Cloud website. Revoked keys are rejected immediately, even if their expiry date has not passed. |
Returns every site the API key's access group can reach, including connectivity status and any currently active schedules.
{- "sites": [
- {
- "siteId": "123e4567-e89b-12d3-a456-426614174000",
- "siteName": "Site 1",
- "isOnline": true,
- "reportedAt": "2025-06-01T08:00:00Z",
- "schedules": [
- {
- "asset": "grid",
- "type": "upperLimitkW",
- "entries": [
- {
- "startAt": "2026-06-01T08:00:00Z",
- "endAt": "2026-06-01T10:00:00Z",
- "value": 50
}
]
}, - {
- "asset": "grid",
- "type": "lowerLimitkW",
- "entries": [
- {
- "startAt": "2026-06-01T08:00:00Z",
- "endAt": "2026-06-01T10:00:00Z",
- "value": -20
}
]
}, - {
- "asset": "grid",
- "type": "activePowerkW",
- "entries": [
- {
- "startAt": "2026-06-01T10:00:00Z",
- "endAt": "2026-06-01T12:00:00Z",
- "value": 30
}
]
}, - {
- "asset": "bess",
- "type": "activePowerkW",
- "entries": [
- {
- "startAt": "2026-06-01T08:00:00Z",
- "endAt": "2026-06-01T10:00:00Z",
- "value": -50
}
]
}, - {
- "asset": "bess",
- "type": "optimalSocPcnt",
- "entries": [
- {
- "startAt": "2026-06-01T10:00:00Z",
- "endAt": "2026-06-01T12:00:00Z",
- "value": 80
}
]
}, - {
- "asset": "solar",
- "type": "solarCurtailmentPcnt",
- "entries": [
- {
- "startAt": "2026-06-01T08:00:00Z",
- "endAt": "2026-06-01T12:00:00Z",
- "value": 10
}
]
}
]
}
]
}Returns the aggregated asset groups (e.g. solar, BESS, EV chargers) configured for the specified site, including rated power and, for BESS, rated energy capacity.
| siteId required | string <uuid> UUID of the site to retrieve |
{- "siteId": "123e4567-e89b-12d3-a456-426614174000",
- "siteName": "Site 1",
- "isOnline": true,
- "reportedAt": "2025-06-01T08:00:00Z",
- "schedules": [
- {
- "asset": "grid",
- "type": "upperLimitkW",
- "entries": [
- {
- "startAt": "2026-06-01T08:00:00Z",
- "endAt": "2026-06-01T10:00:00Z",
- "value": 50
}
]
}, - {
- "asset": "grid",
- "type": "lowerLimitkW",
- "entries": [
- {
- "startAt": "2026-06-01T08:00:00Z",
- "endAt": "2026-06-01T10:00:00Z",
- "value": -20
}
]
}, - {
- "asset": "grid",
- "type": "activePowerkW",
- "entries": [
- {
- "startAt": "2026-06-01T10:00:00Z",
- "endAt": "2026-06-01T12:00:00Z",
- "value": 30
}
]
}, - {
- "asset": "bess",
- "type": "activePowerkW",
- "entries": [
- {
- "startAt": "2026-06-01T08:00:00Z",
- "endAt": "2026-06-01T10:00:00Z",
- "value": -50
}
]
}, - {
- "asset": "bess",
- "type": "optimalSocPcnt",
- "entries": [
- {
- "startAt": "2026-06-01T10:00:00Z",
- "endAt": "2026-06-01T12:00:00Z",
- "value": 80
}
]
}, - {
- "asset": "solar",
- "type": "solarCurtailmentPcnt",
- "entries": [
- {
- "startAt": "2026-06-01T08:00:00Z",
- "endAt": "2026-06-01T12:00:00Z",
- "value": 10
}
]
}
], - "assets": {
- "grid": {
- "id": "0-grid",
- "type": "grid",
- "ratedPowerUpperLimitkW": 500,
- "ratedPowerLowerLimitkW": -500,
- "activePowerkW": 120
}, - "solar": {
- "id": "0-solar",
- "type": "solar",
- "ratedPowerUpperLimitkW": 200,
- "ratedPowerLowerLimitkW": 0,
- "activePowerkW": 150
}, - "bess": {
- "id": "0-bess",
- "type": "bess",
- "ratedPowerUpperLimitkW": 100,
- "ratedPowerLowerLimitkW": -100,
- "activePowerkW": 30,
- "availableStorageCapacitykWh": 500,
- "soc": 75
}, - "ev": {
- "id": "0-ev",
- "type": "ev",
- "ratedPowerUpperLimitkW": 50,
- "ratedPowerLowerLimitkW": 0,
- "activePowerkW": 22
}, - "heatpump": {
- "id": "0-heatpump",
- "type": "heatpump",
- "ratedPowerUpperLimitkW": 20,
- "ratedPowerLowerLimitkW": 0,
- "activePowerkW": 10
}, - "genset": {
- "id": "0-genset",
- "type": "genset",
- "ratedPowerUpperLimitkW": 300,
- "ratedPowerLowerLimitkW": 0,
- "activePowerkW": 0
}, - "load": {
- "id": "0-load",
- "type": "load",
- "ratedPowerUpperLimitkW": 400,
- "ratedPowerLowerLimitkW": 0,
- "activePowerkW": 250
}
}
}Accepts schedule commands for a site. Each command targets an asset with a schedule type and a list of time-range entries. Each asset/type combination must appear at most once — duplicate pairs cause the entire schedule to be rejected. Entries within a command must not overlap in time; any conflict also rejects the entire schedule. upperLimitkW and lowerLimitkW are signed: positive = import, negative = export.
To clear existing schedules of a specific type for a selected asset, send a command with an empty entries array.
Supported asset + type combinations:
grid + upperLimitkW/lowerLimitkW - grid export(negative values) and import (positive values)
grid + activePowerkW - grid active power setpoint
solar + solarCurtailmentPcnt - solar curtailment percentage
bess + activePowerkW - BESS active power setpoint
bess + optimalSocPcnt - BESS optimal state of charge
Note: BESS activePowerkW and optimalSocPcnt are mutually exclusive which practically means 2 things:
activePowerkW schedule command overwrites any existing optimalSocPcnt, and vice versa| siteId required | string <uuid> UUID of the target site |
required | Array of objects (AssetScheduleCommand) [ 1 .. 10 ] items List of asset schedule commands. Each asset/type combination must appear at most once. |
{- "schedules": [
- {
- "asset": "grid",
- "type": "upperLimitkW",
- "entries": [
- {
- "startAt": "2026-06-01T08:00:00Z",
- "endAt": "2026-06-01T10:00:00Z",
- "value": 50
}
]
}, - {
- "asset": "grid",
- "type": "lowerLimitkW",
- "entries": [
- {
- "startAt": "2026-06-01T08:00:00Z",
- "endAt": "2026-06-01T10:00:00Z",
- "value": -20
}
]
}, - {
- "asset": "grid",
- "type": "activePowerkW",
- "entries": [
- {
- "startAt": "2026-06-01T10:00:00Z",
- "endAt": "2026-06-01T12:00:00Z",
- "value": 30
}
]
}, - {
- "asset": "bess",
- "type": "activePowerkW",
- "entries": [
- {
- "startAt": "2026-06-01T08:00:00Z",
- "endAt": "2026-06-01T10:00:00Z",
- "value": -50
}
]
}, - {
- "asset": "bess",
- "type": "optimalSocPcnt",
- "entries": [
- {
- "startAt": "2026-06-01T10:00:00Z",
- "endAt": "2026-06-01T12:00:00Z",
- "value": 80
}
]
}, - {
- "asset": "solar",
- "type": "solarCurtailmentPcnt",
- "entries": [
- {
- "startAt": "2026-06-01T08:00:00Z",
- "endAt": "2026-06-01T12:00:00Z",
- "value": 10
}
]
}
]
}{- "batchId": "5579c111-9c50-47e2-af92-f16d52e63189",
- "accepted": 0
}Returns 204 when the service is operational, 503 when unavailable. Request timeouts should also be treated as service unavailability.
{- "error": "internal_server_error",
- "message": "An unexpected error occurred"
}