GridMango API Reference (v1)
Integrate GridMango baseline analytics, synthetic interval data generation, and simulated DER workflows into your operational engineering and validation processes.
Base URL: https://gridmango.com/api/v1
Bearer-token access through your signed-in GridMango account.
Request/response JSON for baseline analysis, synthetic data generation, and DER registry workflows.
Authentication
- Sign in to your GridMango account.
- Open Profile and go to API Access.
- Copy your current bearer token.
- Send the token in the request header:
Authorization: Bearer <token>
Tokens are session-scoped. Rotate them as part of your own integration lifecycle and avoid embedding them in shared scripts or client-side logs.
Integration Security Practices
- Use HTTPS only and transmit bearer tokens through the
Authorizationheader. - Implement retry with backoff for transient failures and alert on repeated
errorCodevalues. - Capture
supportCodevalues from failed responses so incidents can be traced quickly with GridMango support.
Entitlements and Feature Gating
Access is enforced by the account’s active plan. Use the matrix below to align your integration surface with the subscription tier you intend to provision.
| Endpoint | Starter | Professional | Platform |
|---|---|---|---|
POST /baseline/generate |
✓ | ✓ | ✓ |
POST /load-shape/generate |
✓ | ✓ | ✓ |
POST /telemetry-simulator/generate |
✕ | ✓ | ✓ |
POST /der-devices/list |
✕ | ✓ | ✓ |
POST /der-devices/upsert |
✕ | ✓ | ✓ |
POST /der-devices/delete |
✕ | ✓ | ✓ |
POST /matter/mem/tests/start |
✕ | ✕ | ✓ |
POST /matter/mem/tests/list |
✕ | ✕ | ✓ |
POST /matter/mem/tests/get |
✕ | ✕ | ✓ |
API access follows the account’s active subscription. Requests outside the active entitlement set are rejected.
DER API Limits
The DER registry and telemetry simulator are designed for engineering-scale workflows. Use these request limits when planning batch orchestration and fleet simulation jobs.
| Limit | Professional | Platform |
|---|---|---|
| Saved DER devices per account | 500 | 1,500 |
| DER upsert items per request | 200 | 200 |
| Telemetry range per generate request | 7 days | 30 days |
Telemetry generation is deterministic. Identical requests for the same DER, range, and configuration produce identical output.
Code Examples by Endpoint
Each public endpoint includes copy-ready cURL, Python, and Node.js examples, a concise field dictionary, and a representative success response that mirrors the production response envelope.
POST /baseline/generate
Generate a demand response baseline and event-performance summary from interval telemetry.
curl -X POST "https://gridmango.com/api/v1/baseline/generate" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer <your-session-token>" \
-d '{
"telemetryRows": [
{ "Time": "2026-03-10T16:00:00.000Z", "kW": 2.91 },
{ "Time": "2026-03-10T16:15:00.000Z", "kW": 2.88 },
{ "Time": "2026-03-10T16:30:00.000Z", "kW": 2.74 },
{ "Time": "2026-03-10T16:45:00.000Z", "kW": 2.52 }
],
"event": {
"eventDate": "2026-03-18",
"eventTime": "17:00",
"duration": 60,
"direction": "import"
},
"baseline": {
"method": "xofy",
"x": 3,
"y": 8,
"similarDayMode": "match_event_day",
"timestampConvention": "start",
"excludeHolidays": true,
"holidays": ["2026-02-16", "2026-03-17"]
},
"sameDayAdjustment": {
"enabled": true,
"startTime": "14:00",
"endTime": "16:00",
"method": "additive",
"positiveCapPct": 20,
"negativeCapPct": 20,
"minFactor": 0.8,
"maxFactor": 1.2
}
}'
import requests
base_url = "https://gridmango.com/api/v1"
token = "your-session-token"
payload = {
"telemetryRows": [
{"Time": "2026-03-10T16:00:00.000Z", "kW": 2.91},
{"Time": "2026-03-10T16:15:00.000Z", "kW": 2.88},
{"Time": "2026-03-10T16:30:00.000Z", "kW": 2.74},
{"Time": "2026-03-10T16:45:00.000Z", "kW": 2.52}
],
"event": {
"eventDate": "2026-03-18",
"eventTime": "17:00",
"duration": 60,
"direction": "import"
},
"baseline": {
"method": "xofy",
"x": 3,
"y": 8,
"similarDayMode": "match_event_day",
"timestampConvention": "start",
"excludeHolidays": True,
"holidays": ["2026-02-16", "2026-03-17"]
},
"sameDayAdjustment": {
"enabled": True,
"startTime": "14:00",
"endTime": "16:00",
"method": "additive",
"positiveCapPct": 20,
"negativeCapPct": 20,
"minFactor": 0.8,
"maxFactor": 1.2
}
}
resp = requests.post(
f"{base_url}/baseline/generate",
headers={"Authorization": f"Bearer {token}", "Content-Type": "application/json"},
json=payload,
timeout=60
)
resp.raise_for_status()
print(resp.json())
const baseUrl = 'https://gridmango.com/api/v1';
const token = 'your-session-token';
const payload = {
telemetryRows: [
{ Time: '2026-03-10T16:00:00.000Z', kW: 2.91 },
{ Time: '2026-03-10T16:15:00.000Z', kW: 2.88 },
{ Time: '2026-03-10T16:30:00.000Z', kW: 2.74 },
{ Time: '2026-03-10T16:45:00.000Z', kW: 2.52 }
],
event: {
eventDate: '2026-03-18',
eventTime: '17:00',
duration: 60,
direction: 'import'
},
baseline: {
method: 'xofy',
x: 3,
y: 8,
similarDayMode: 'match_event_day',
timestampConvention: 'start',
excludeHolidays: true,
holidays: ['2026-02-16', '2026-03-17']
},
sameDayAdjustment: {
enabled: true,
startTime: '14:00',
endTime: '16:00',
method: 'additive',
positiveCapPct: 20,
negativeCapPct: 20,
minFactor: 0.8,
maxFactor: 1.2
}
};
const response = await fetch(`${baseUrl}/baseline/generate`, {
method: 'POST',
headers: { 'Content-Type': 'application/json', Authorization: `Bearer ${token}` },
body: JSON.stringify(payload)
});
if (!response.ok) throw new Error(`Request failed: ${response.status}`);
console.log(await response.json());
| Field | Details |
|---|---|
telemetryRows or rows | Required array of interval telemetry. GridMango detects the time column and the load/value column from the supplied row keys. |
event.eventDate | Required event day in YYYY-MM-DD format. |
event.eventTime | Required event start time in HH:MM format. |
event.duration | Required event duration in minutes. Allowed range: 1 to 1440. |
event.direction | Optional. Supported values: import, export. Default: import. |
baseline.method | Optional. Supported values: xofy, xofy_middle, nearest_like_days, day_matching_average, median_candidates, ewma, mbma. Default: xofy. |
baseline.x / baseline.y | For xofy and xofy_middle, both are required (1-20) and x <= y. For nearest_like_days, use y as nearest-day count (1-20). For day_matching_average, median_candidates, and ewma, y controls candidate count. mbma ignores X/Y. |
baseline.similarDayMode | Optional. Recommended values: match_event_day, weekdays_only, weekends_only. Default: match_event_day. |
baseline.timestampConvention | Optional. Supported values: start, end. Default: start. Top-level timestampConvention is also accepted. |
baseline.excludeHolidays | Optional boolean. Excludes listed holiday dates from baseline candidate selection. Top-level excludeHolidays is also accepted. |
baseline.holidays | Optional array of holiday dates in YYYY-MM-DD format. Top-level holidays is also accepted. |
sameDayAdjustment | Optional object. Supported fields: enabled, startTime, endTime, method (additive or multiplicative), positiveCapPct, negativeCapPct, minFactor, and maxFactor. Additive mode uses the positive/negative caps. Multiplicative mode uses the factor bounds. |
Example Success Response
{
"ok": true,
"version": "v1",
"data": {
"summary": {
"method": "xofy",
"methodLabel": "X of Y (Highest Usage)",
"candidateCount": 8,
"selectedCount": 3,
"unadjustedBaselineTotalKw": 10.21,
"eventPerformanceAvgKw": 1.87,
"eventPerformanceTotalKw": 7.48,
"eventEnergyDeliveredKwh": 1.87,
"eventPerformancePct": 18.32,
"adjustedBaselineTotalKw": 10.68,
"adjustedEventPerformanceAvgKw": 2.34,
"adjustedEventPerformanceTotalKw": 9.36,
"adjustedEventEnergyDeliveredKwh": 2.34,
"adjustedEventPerformancePct": 21.91,
"sda": {
"enabled": true,
"method": "additive",
"delta": 0.12,
"positiveCapPct": 20,
"negativeCapPct": 20,
"minFactor": 0.8,
"maxFactor": 1.2
}
},
"selectedDays": ["2026-03-04", "2026-03-05", "2026-03-11"],
"timeseries": [
{ "time": "17:00", "baseline": 2.64, "adjustedBaseline": 2.76, "actual": 2.21 },
{ "time": "17:15", "baseline": 2.58, "adjustedBaseline": 2.70, "actual": 2.09 }
]
},
"meta": {
"buildId": "prod",
"runtime": "netlify"
}
}
POST /load-shape/generate
Create synthetic site- or meter-level interval telemetry for baseline studies, replay validation, and downstream analytics testing.
curl -X POST "https://gridmango.com/api/v1/load-shape/generate" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer <your-session-token>" \
-d '{
"startDateTime": "2026-04-01T00:00:00.000Z",
"endDateTime": "2026-04-07T23:45:00.000Z",
"intervalMins": 15,
"channel": "net",
"minKw": 1.5,
"maxKw": 5.5,
"randomness": 0.08,
"peakHoursEnabled": true,
"peakStartTime": "16:00",
"peakEndTime": "21:00",
"peakLiftPct": 25,
"timestampMode": "named",
"timestampTimeZone": "America/Los_Angeles"
}'
import requests
base_url = "https://gridmango.com/api/v1"
token = "your-session-token"
payload = {
"startDateTime": "2026-04-01T00:00:00.000Z",
"endDateTime": "2026-04-07T23:45:00.000Z",
"intervalMins": 15,
"channel": "net",
"minKw": 1.5,
"maxKw": 5.5,
"randomness": 0.08,
"peakHoursEnabled": True,
"peakStartTime": "16:00",
"peakEndTime": "21:00",
"peakLiftPct": 25,
"timestampMode": "named",
"timestampTimeZone": "America/Los_Angeles"
}
resp = requests.post(
f"{base_url}/load-shape/generate",
headers={"Authorization": f"Bearer {token}", "Content-Type": "application/json"},
json=payload,
timeout=60
)
resp.raise_for_status()
print(resp.json())
const baseUrl = 'https://gridmango.com/api/v1';
const token = 'your-session-token';
const payload = {
startDateTime: '2026-04-01T00:00:00.000Z',
endDateTime: '2026-04-07T23:45:00.000Z',
intervalMins: 15,
channel: 'net',
minKw: 1.5,
maxKw: 5.5,
randomness: 0.08,
peakHoursEnabled: true,
peakStartTime: '16:00',
peakEndTime: '21:00',
peakLiftPct: 25,
timestampMode: 'named',
timestampTimeZone: 'America/Los_Angeles'
};
const response = await fetch(`${baseUrl}/load-shape/generate`, {
method: 'POST',
headers: { 'Content-Type': 'application/json', Authorization: `Bearer ${token}` },
body: JSON.stringify(payload)
});
if (!response.ok) throw new Error(`Request failed: ${response.status}`);
console.log(await response.json());
| Field | Details |
|---|---|
startDateTime + endDateTime | Preferred request window in ISO datetime format. Required for new integrations. |
startDate + days | Legacy compatibility input. startDate uses YYYY-MM-DD. days must be 1-365. |
intervalMins | Required. Allowed range: 1-60. |
channel | Optional. Supported values: net, import, export. Default: net. |
minKw / maxKw | Required numeric bounds with maxKw >= minKw. |
randomness | Optional randomization factor from 0 to 1. Alias: noise. Default: 0.15. |
peakHoursEnabled | Optional boolean. Enables peak/off-peak shaping. |
peakStartTime / peakEndTime | Optional HH:MM peak window when peak shaping is enabled. |
peakLiftPct | Optional. Allowed range when enabled: 1-100. Default: 30. |
timestampMode | Optional. Supported values: utc, named, browser_local. Default: utc. |
timestampTimeZone | Optional named timezone used when timestampMode is named. Default: UTC. |
Example Success Response
{
"ok": true,
"version": "v1",
"data": {
"buildingType": "multifamily",
"profileType": "multifamily",
"channel": "net",
"startDate": "",
"startDateTime": "2026-04-01T00:00:00.000Z",
"endDateTime": "2026-04-07T23:45:00.000Z",
"days": 6.989583,
"intervalMins": 15,
"peakHoursEnabled": true,
"peakStartTime": "16:00",
"peakEndTime": "21:00",
"peakLiftPct": 25,
"rowCount": 672,
"rows": [
{ "Time": "2026-04-01T00:00:00.000-07:00", "kW": 1.86 },
{ "Time": "2026-04-01T00:15:00.000-07:00", "kW": 1.79 },
{ "Time": "2026-04-01T00:30:00.000-07:00", "kW": 1.74 }
]
},
"meta": {
"buildId": "prod",
"runtime": "netlify"
}
}
POST /der-devices/list
List DER devices saved under the authenticated account for simulator workflows.
curl -X POST "https://gridmango.com/api/v1/der-devices/list" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer <your-session-token>" \
-d '{}'
import requests
base_url = "https://gridmango.com/api/v1"
token = "your-session-token"
resp = requests.post(
f"{base_url}/der-devices/list",
headers={"Authorization": f"Bearer {token}", "Content-Type": "application/json"},
json={},
timeout=60
)
resp.raise_for_status()
print(resp.json())
const baseUrl = 'https://gridmango.com/api/v1';
const token = 'your-session-token';
const response = await fetch(`${baseUrl}/der-devices/list`, {
method: 'POST',
headers: { 'Content-Type': 'application/json', Authorization: `Bearer ${token}` },
body: JSON.stringify({})
});
if (!response.ok) throw new Error(`Request failed: ${response.status}`);
console.log(await response.json());
Example Success Response
{
"ok": true,
"version": "v1",
"data": {
"devices": [
{
"id": "9f5f5d54-5a6a-4c97-a7aa-8e1f58b8a6f5",
"deviceId": "der-0001",
"displayName": "Battery Alpha",
"derType": "battery_storage",
"ratedPowerKw": 7.5,
"storedEnergyKwh": 15,
"minSoc": 10,
"maxSoc": 95,
"defaults": {
"uom": "kW",
"channel": "net",
"intervalMins": 15,
"timezone": "UTC"
}
}
]
},
"meta": {
"buildId": "prod",
"runtime": "netlify"
}
}
POST /der-devices/upsert
Create or update one DER device or bulk upsert a DER device set for simulator workflows.
curl -X POST "https://gridmango.com/api/v1/der-devices/upsert" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer <your-session-token>" \
-d '{
"device": {
"deviceId": "der-0001",
"displayName": "Battery Alpha",
"derType": "battery_storage",
"ratedPowerKw": 7.5,
"storedEnergyKwh": 15,
"minSoc": 10,
"maxSoc": 95,
"defaults": {
"uom": "kW",
"channel": "net",
"intervalMins": 15,
"timezone": "UTC",
"baseValue": 0.8,
"peakValue": 7.5,
"peakHoursEnabled": true,
"peakStartTime": "16:00",
"peakEndTime": "21:00",
"peakLiftPct": 30
}
}
}'
import requests
base_url = "https://gridmango.com/api/v1"
token = "your-session-token"
payload = {
"device": {
"deviceId": "der-0001",
"displayName": "Battery Alpha",
"derType": "battery_storage",
"ratedPowerKw": 7.5,
"storedEnergyKwh": 15,
"minSoc": 10,
"maxSoc": 95,
"defaults": {
"uom": "kW",
"channel": "net",
"intervalMins": 15,
"timezone": "UTC",
"baseValue": 0.8,
"peakValue": 7.5,
"peakHoursEnabled": True,
"peakStartTime": "16:00",
"peakEndTime": "21:00",
"peakLiftPct": 30
}
}
}
resp = requests.post(
f"{base_url}/der-devices/upsert",
headers={"Authorization": f"Bearer {token}", "Content-Type": "application/json"},
json=payload,
timeout=60
)
resp.raise_for_status()
print(resp.json())
const baseUrl = 'https://gridmango.com/api/v1';
const token = 'your-session-token';
const payload = {
device: {
deviceId: 'der-0001',
displayName: 'Battery Alpha',
derType: 'battery_storage',
ratedPowerKw: 7.5,
storedEnergyKwh: 15,
minSoc: 10,
maxSoc: 95,
defaults: {
uom: 'kW',
channel: 'net',
intervalMins: 15,
timezone: 'UTC',
baseValue: 0.8,
peakValue: 7.5,
peakHoursEnabled: true,
peakStartTime: '16:00',
peakEndTime: '21:00',
peakLiftPct: 30
}
}
};
const response = await fetch(`${baseUrl}/der-devices/upsert`, {
method: 'POST',
headers: { 'Content-Type': 'application/json', Authorization: `Bearer ${token}` },
body: JSON.stringify(payload)
});
if (!response.ok) throw new Error(`Request failed: ${response.status}`);
console.log(await response.json());
| Field | Details |
|---|---|
device or devices | Send a single DER under device or bulk upsert under devices. Maximum bulk size: 200. |
deviceId | Required. Unique per account. Allowed pattern: letters, numbers, dot, underscore, colon, hyphen. Length: 3-80. |
displayName | Optional user-facing label. |
derType | Required. Supported values: battery_storage, ev_charger, solar_pv, hvac_load, standby_generator. |
ratedPowerKw | Required positive number. Maximum: 50000. |
storedEnergyKwh | Optional numeric value. |
minSoc / maxSoc | Optional percentage bounds from 0 to 100. minSoc cannot exceed maxSoc. |
defaults | Optional simulator defaults merged into future telemetry calls for the DER. Recommended fields: uom, channel, intervalMins, timezone, baseValue, peakValue, peakHoursEnabled, peakStartTime, peakEndTime, peakLiftPct. |
| Aliases | Snake-case payload keys are accepted for compatibility, including device_id, display_name, der_type, rated_power_kw, stored_energy_kwh, min_soc, and max_soc. |
Example Success Response
{
"ok": true,
"version": "v1",
"data": {
"devices": [
{
"id": "9f5f5d54-5a6a-4c97-a7aa-8e1f58b8a6f5",
"deviceId": "der-0001",
"displayName": "Battery Alpha",
"derType": "battery_storage",
"ratedPowerKw": 7.5,
"storedEnergyKwh": 15,
"minSoc": 10,
"maxSoc": 95,
"defaults": {
"uom": "kW",
"channel": "net",
"intervalMins": 15,
"timezone": "UTC",
"baseValue": 0.8,
"peakValue": 7.5
}
}
]
},
"meta": {
"buildId": "prod",
"runtime": "netlify"
}
}
POST /der-devices/delete
Delete saved DER devices by internal record id or by the account-scoped DER device id.
curl -X POST "https://gridmango.com/api/v1/der-devices/delete" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer <your-session-token>" \
-d '{
"deviceIds": ["der-0001"]
}'
import requests
base_url = "https://gridmango.com/api/v1"
token = "your-session-token"
payload = {"deviceIds": ["der-0001"]}
resp = requests.post(
f"{base_url}/der-devices/delete",
headers={"Authorization": f"Bearer {token}", "Content-Type": "application/json"},
json=payload,
timeout=60
)
resp.raise_for_status()
print(resp.json())
const baseUrl = 'https://gridmango.com/api/v1';
const token = 'your-session-token';
const payload = { deviceIds: ['der-0001'] };
const response = await fetch(`${baseUrl}/der-devices/delete`, {
method: 'POST',
headers: { 'Content-Type': 'application/json', Authorization: `Bearer ${token}` },
body: JSON.stringify(payload)
});
if (!response.ok) throw new Error(`Request failed: ${response.status}`);
console.log(await response.json());
| Field | Details |
|---|---|
ids | Optional array of internal GridMango record ids. |
deviceIds | Optional array of account-scoped DER device ids. |
| Requirement | Provide at least one of ids or deviceIds. |
Example Success Response
{
"ok": true,
"version": "v1",
"data": {
"deletedIds": ["9f5f5d54-5a6a-4c97-a7aa-8e1f58b8a6f5"],
"count": 1
},
"meta": {
"buildId": "prod",
"runtime": "netlify"
}
}
POST /telemetry-simulator/generate
Generate deterministic synthetic DER telemetry either from a saved DER profile or from a direct request payload.
curl -X POST "https://gridmango.com/api/v1/telemetry-simulator/generate" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer <your-session-token>" \
-d '{
"deviceId": "der-0001",
"startDateTime": "2026-04-01T00:00:00.000Z",
"endDateTime": "2026-04-07T23:45:00.000Z",
"intervalMins": 15,
"channel": "net",
"uom": "kW",
"timestampMode": "named",
"timestampTimeZone": "UTC",
"baseValue": 0.5,
"peakValue": 7.5,
"randomness": 0.2,
"peakHoursEnabled": true,
"peakStartTime": "16:00",
"peakEndTime": "21:00",
"peakLiftPct": 30
}'
import requests
base_url = "https://gridmango.com/api/v1"
token = "your-session-token"
payload = {
"deviceId": "der-0001",
"startDateTime": "2026-04-01T00:00:00.000Z",
"endDateTime": "2026-04-07T23:45:00.000Z",
"intervalMins": 15,
"channel": "net",
"uom": "kW",
"timestampMode": "named",
"timestampTimeZone": "UTC",
"baseValue": 0.5,
"peakValue": 7.5,
"randomness": 0.2,
"peakHoursEnabled": True,
"peakStartTime": "16:00",
"peakEndTime": "21:00",
"peakLiftPct": 30
}
resp = requests.post(
f"{base_url}/telemetry-simulator/generate",
headers={"Authorization": f"Bearer {token}", "Content-Type": "application/json"},
json=payload,
timeout=60
)
resp.raise_for_status()
print(resp.json())
const baseUrl = 'https://gridmango.com/api/v1';
const token = 'your-session-token';
const payload = {
deviceId: 'der-0001',
startDateTime: '2026-04-01T00:00:00.000Z',
endDateTime: '2026-04-07T23:45:00.000Z',
intervalMins: 15,
channel: 'net',
uom: 'kW',
timestampMode: 'named',
timestampTimeZone: 'UTC',
baseValue: 0.5,
peakValue: 7.5,
randomness: 0.2,
peakHoursEnabled: true,
peakStartTime: '16:00',
peakEndTime: '21:00',
peakLiftPct: 30
};
const response = await fetch(`${baseUrl}/telemetry-simulator/generate`, {
method: 'POST',
headers: { 'Content-Type': 'application/json', Authorization: `Bearer ${token}` },
body: JSON.stringify(payload)
});
if (!response.ok) throw new Error(`Request failed: ${response.status}`);
console.log(await response.json());
| Field | Details |
|---|---|
deviceId | Optional saved DER id. When supplied, stored DER defaults are merged into the request before simulation runs. |
startDateTime + endDateTime | Preferred request window in ISO datetime format. |
startDate + days | Legacy compatibility input. Used only when datetime fields are omitted. |
intervalMins | Required. Allowed range: 1-60. |
derType | Optional when deviceId is used. Supported values: battery_storage, ev_charger, solar_pv, hvac_load, standby_generator. |
uom | Supported by DER type: battery_storage, ev_charger, solar_pv support kW, W, MW; hvac_load supports kW, RT; standby_generator supports kW, MW, kVA. |
channel | Optional. Supported values: net, import, export. Default: net. |
baseValue / peakValue | Optional numeric operating bounds. peakValue must be greater than or equal to baseValue. |
randomness | Optional factor from 0 to 1. Default: 0.2. |
peakHoursEnabled, peakStartTime, peakEndTime, peakLiftPct | Optional peak/off-peak shaping controls. peakLiftPct range when enabled: 1-100. |
timestampMode | Optional. Supported values: utc, named, browser_local. Default in direct requests: utc. Saved DER defaults may set named. |
timestampTimeZone | Optional named timezone used when timestampMode is named. Default: UTC. |
| Plan limits | Professional requests are limited to 7 days per call. Platform requests are limited to 30 days per call. |
Example Success Response
{
"ok": true,
"version": "v1",
"data": {
"derType": "battery_storage",
"derLabel": "Battery Storage",
"climateZone": "mild",
"channel": "net",
"startDateTime": "2026-04-01T00:00:00.000Z",
"endDateTime": "2026-04-07T23:45:00.000Z",
"days": 6.989583,
"intervalMins": 15,
"peakHoursEnabled": true,
"peakStartTime": "16:00",
"peakEndTime": "21:00",
"peakLiftPct": 30,
"uom": "kW",
"rowCount": 672,
"telemetryRows": [
{ "timestamp": "2026-04-01T00:00:00.000Z", "kW": 0.62 },
{ "timestamp": "2026-04-01T00:15:00.000Z", "kW": 0.58 },
{ "timestamp": "2026-04-01T00:30:00.000Z", "kW": 0.61 }
],
"weatherRows": [
{ "timestamp": "2026-04-01T00:00:00.000Z", "temperatureF": 58.2, "relativeHumidityPct": 64.1, "globalHorizontalIrradianceWm2": 0 },
{ "timestamp": "2026-04-01T00:15:00.000Z", "temperatureF": 58.1, "relativeHumidityPct": 64.5, "globalHorizontalIrradianceWm2": 0 }
],
"baselineProfileRows": [
{ "time": "00:00", "kW": 0.62 },
{ "time": "00:15", "kW": 0.58 }
]
},
"meta": {
"buildId": "prod",
"runtime": "netlify"
}
}
POST /matter/mem/tests/start
Create and execute a Matter Energy Management conformance run using one shared DER device profile.
curl -X POST "https://gridmango.com/api/v1/matter/mem/tests/start" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer <your-session-token>" \
-d '{
"deviceProfileId": "9f5f5d54-5a6a-4c97-a7aa-8e1f58b8a6f5",
"scenarioType": "dr_load_shed",
"matterVersion": "1.4",
"endpoint": "wss://device-gateway.example/ws",
"authMode": "token",
"authConfig": { "bearerToken": "token-value" },
"expectedResponseMs": 2000,
"commandTimeoutMs": 6000,
"telemetryWindowMins": 30,
"telemetryIntervalMins": 5
}'
import requests
base_url = "https://gridmango.com/api/v1"
token = "your-session-token"
payload = {
"deviceProfileId": "9f5f5d54-5a6a-4c97-a7aa-8e1f58b8a6f5",
"scenarioType": "dr_load_shed",
"matterVersion": "1.4",
"endpoint": "wss://device-gateway.example/ws",
"authMode": "token",
"authConfig": {"bearerToken": "token-value"},
"expectedResponseMs": 2000,
"commandTimeoutMs": 6000,
"telemetryWindowMins": 30,
"telemetryIntervalMins": 5
}
resp = requests.post(
f"{base_url}/matter/mem/tests/start",
headers={"Authorization": f"Bearer {token}", "Content-Type": "application/json"},
json=payload,
timeout=60
)
resp.raise_for_status()
print(resp.json())
const baseUrl = 'https://gridmango.com/api/v1';
const token = 'your-session-token';
const payload = {
deviceProfileId: '9f5f5d54-5a6a-4c97-a7aa-8e1f58b8a6f5',
scenarioType: 'dr_load_shed',
matterVersion: '1.4',
endpoint: 'wss://device-gateway.example/ws',
authMode: 'token',
authConfig: { bearerToken: 'token-value' },
expectedResponseMs: 2000,
commandTimeoutMs: 6000,
telemetryWindowMins: 30,
telemetryIntervalMins: 5
};
const response = await fetch(`${baseUrl}/matter/mem/tests/start`, {
method: 'POST',
headers: { 'Content-Type': 'application/json', Authorization: `Bearer ${token}` },
body: JSON.stringify(payload)
});
if (!response.ok) throw new Error(`Request failed: ${response.status}`);
console.log(await response.json());
| Field | Details |
|---|---|
deviceProfileId or deviceId | Required. Use a shared DER profile id or DER device id from your registry. Supported DER types: ev_charger, battery_storage, hvac_load, solar_pv. |
scenarioType | Optional. Supported values: dr_load_shed, smart_charging, availability. Default: dr_load_shed. |
matterVersion | Optional. Supported values: 1.3, 1.4. Default: 1.4. |
endpoint | Optional websocket endpoint. Must begin with ws:// or wss://. |
authMode | Optional. Supported values: none, token, basic, mtls. Default: none. |
authConfig | Required when auth mode is not none. token: bearerToken. basic: username + password. mtls: clientCertPem + clientKeyPem and optional caCertPem. |
expectedResponseMs | Optional integer, 250-20000. Default: 2000. |
commandTimeoutMs | Optional integer, 1000-30000. Default: 6000. |
telemetryWindowMins | Optional integer, 5-1440. Default: 30. |
telemetryIntervalMins | Optional integer, 1-60. Default: 5. |
simulateFailure | Optional boolean to intentionally trigger a failing control-response branch for QA validation. |
POST /matter/mem/tests/list
List recent Matter MEM test runs for the authenticated account.
curl -X POST "https://gridmango.com/api/v1/matter/mem/tests/list" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer <your-session-token>" \
-d '{ "limit": 20 }'
import requests
base_url = "https://gridmango.com/api/v1"
token = "your-session-token"
resp = requests.post(
f"{base_url}/matter/mem/tests/list",
headers={"Authorization": f"Bearer {token}", "Content-Type": "application/json"},
json={"limit": 20},
timeout=60
)
resp.raise_for_status()
print(resp.json())
const baseUrl = 'https://gridmango.com/api/v1';
const token = 'your-session-token';
const response = await fetch(`${baseUrl}/matter/mem/tests/list`, {
method: 'POST',
headers: { 'Content-Type': 'application/json', Authorization: `Bearer ${token}` },
body: JSON.stringify({ limit: 20 })
});
if (!response.ok) throw new Error(`Request failed: ${response.status}`);
console.log(await response.json());
| Field | Details |
|---|---|
limit | Optional integer from 1 to 100. Default: 20. |
POST /matter/mem/tests/get
Fetch one Matter MEM test run with suite-level outcomes and timeline entries.
curl -X POST "https://gridmango.com/api/v1/matter/mem/tests/get" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer <your-session-token>" \
-d '{ "runId": "f3d17f4f-8b39-4e5a-8cdb-5f3f6776f6a2" }'
import requests
base_url = "https://gridmango.com/api/v1"
token = "your-session-token"
resp = requests.post(
f"{base_url}/matter/mem/tests/get",
headers={"Authorization": f"Bearer {token}", "Content-Type": "application/json"},
json={"runId": "f3d17f4f-8b39-4e5a-8cdb-5f3f6776f6a2"},
timeout=60
)
resp.raise_for_status()
print(resp.json())
const baseUrl = 'https://gridmango.com/api/v1';
const token = 'your-session-token';
const response = await fetch(`${baseUrl}/matter/mem/tests/get`, {
method: 'POST',
headers: { 'Content-Type': 'application/json', Authorization: `Bearer ${token}` },
body: JSON.stringify({ runId: 'f3d17f4f-8b39-4e5a-8cdb-5f3f6776f6a2' })
});
if (!response.ok) throw new Error(`Request failed: ${response.status}`);
console.log(await response.json());
| Field | Details |
|---|---|
runId | Required Matter MEM run id from /matter/mem/tests/list or /matter/mem/tests/start. |
Example Success Response
{
"ok": true,
"version": "v1",
"data": {
"run": {
"id": "f3d17f4f-8b39-4e5a-8cdb-5f3f6776f6a2",
"deviceId": "ev-fleet-01",
"scenarioType": "dr_load_shed",
"status": "completed",
"resultSummary": {
"verdict": "pass_with_exceptions",
"score": 86.25,
"kpis": { "commandLatencyMs": 1420, "telemetryRowsChecked": 12, "suitesPassed": 3, "suitesTotal": 4 },
"suites": [{ "name": "control_response", "passCount": 3, "totalCount": 4, "failCount": 1 }],
"findings": [{ "severity": "major", "code": "telemetry_resolution", "message": "Telemetry interval is coarse; use 15 minutes or lower for stronger conformance evidence." }]
}
},
"timeline": [
{ "eventType": "run_queued", "level": "info", "message": "Matter MEM test run queued.", "createdAt": "2026-04-22T01:19:00.100Z" },
{ "eventType": "run_completed", "level": "info", "message": "Matter MEM test completed.", "createdAt": "2026-04-22T01:19:01.942Z" }
]
}
}
Endpoint Reference
Use this section as a quick route index when wiring clients or validating entitlement scope. Detailed request and response examples appear above.
POST /baseline/generate
Generate baseline and event-performance outputs from interval telemetry and saved calibration rules.
POST /load-shape/generate
Create synthetic site- or meter-level interval load series for baseline QA and analytics validation.
POST /telemetry-simulator/generate
Generate deterministic synthetic DER telemetry from a direct request or a saved DER profile.
POST /der-devices/list
List all saved DER profiles available to the authenticated account.
POST /der-devices/upsert
Create or update one DER or bulk upsert a managed DER registry for simulator workflows.
POST /der-devices/delete
Delete saved DER profiles by internal ids or external DER device ids.
POST /matter/mem/tests/start
Start a Matter Energy Management conformance run for a shared DER device profile.
POST /matter/mem/tests/list
List recent Matter MEM test runs for the authenticated account.
POST /matter/mem/tests/get
Get one Matter MEM run with suite-level outcomes and timeline entries.
Error Response Format
Failed requests return a customer-safe error message, a stable error code, and a support reference suitable for troubleshooting without exposing backend internals.
{
"ok": false,
"error": "Request could not be processed. (Ref: GM-API-AB12CD34)",
"supportCode": "GM-API-AB12CD34",
"errorCode": "validation_failed",
"errorHelp": "Request validation failed. Review inputs and retry."
}
Operator note: capture the supportCode from any failed request in your logs or incident ticket. It is the fastest way for GridMango support to trace the exact failure path without asking for raw customer telemetry.