API Documentation
Complete reference for the IoT Edge Data API v1.0
Authentication
All API requests require authentication using a 64-character API key. API keys are environment-specific (sandbox or production) and must be included in the request headers.
Required Header
X-API-Key: {your-64-character-api-key}
Key Properties
- 64-character random string
- Environment-specific (sandbox keys only work in sandbox, production keys only in production)
- Can have expiration dates
- Associated with device whitelists
Example Request
curl -X GET \
https://api.enpact.iote.uk/api/v1/devices/esl-nt3-5555A1B2C3D4/data?timestamp=2025-08-03T10:00:00+00:00 \
-H 'X-API-Key: your-64-character-api-key-here-1234567890abcdef1234567890abcdef'
Important: Sandbox API keys will only work with sandbox endpoints, and production keys only with production endpoints.
Environments
The API automatically detects the environment based on the hostname. Sandbox environments are identified by hostnames starting with "sandbox-".
Production
Live environment with real device and meter data
https://api.enpact.iote.uk/api/v1
- • Rate limit: 300 req/15 min (all endpoints)
- • Real device and meter data
- • Production API keys only
Sandbox
Test environment with mock data
https://sandbox-api.enpact.iote.uk/api/v1
- • Rate limit: 30 req/sec (all endpoints)
- • Consistent mock data
- • Sandbox API keys only
- • Test device and meter IDs available
Device Endpoints
The IoT Edge API provides endpoints for retrieving temperature and energy saver data from cooling devices. All data is returned for a 15-minute window starting from the specified timestamp.
GET List Devices
/api/v1/devices
Retrieve a list of all available device IDs that are accessible with your API key. This endpoint returns only the device IDs that are whitelisted for your API key.
Example Request
curl -X GET \
https://api.enpact.iote.uk/api/v1/devices \
-H 'X-API-Key: your-64-character-api-key'
Example Response (Production)
{
"devices": [
"esl-nt3-5555A1B2C3D4",
"esl-nt3-5555E5F6A7B8",
"esl-nt3-5555C9D0E1F2"
],
"meta": {
"count": 3,
"environment": "production"
}
}
Example Response (Sandbox)
{
"devices": [
"esl-nt3-test-device-001",
"esl-nt3-test-device-002",
"esl-nt3-test-device-003",
"esl-nt3-test-device-004",
"esl-nt3-test-device-005"
],
"meta": {
"count": 5,
"environment": "sandbox"
}
}
Note: In sandbox environment, this endpoint returns predefined test device IDs. In production, it returns only the devices whitelisted for your API key.
GET Get Device Data
/api/v1/devices/{deviceId}/data
Retrieve data for a single device. Returns 15 minutes of data starting from the specified timestamp.
Path Parameters
| Parameter | Type | Description |
|---|---|---|
| deviceId | string | Unique identifier of the device |
Query Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
| timestamp | ISO 8601 | Yes | Start time (format: Y-m-d\TH:i:s\Z). Must be within last 24 hours |
| aggregation | string | No | "none" for raw data or "15min" for aggregated (default: 15min) |
Example Request
curl -X GET \
'https://api.enpact.iote.uk/api/v1/devices/esl-nt3-5555A1B2C3D4/data?timestamp=2025-08-03T10:00:00+00:00&aggregation=none' \
-H 'X-API-Key: your-64-character-api-key'
POST Batch Device Data
/api/v1/devices/batch/data
Retrieve data for multiple devices in a single request. Returns 15 minutes of data for each device starting from the specified timestamp. Maximum 150 devices per request.
Request Body
{
"deviceIds": [
"esl-nt3-5555A1B2C3D4",
"esl-nt3-5555E5F6A7B8",
"esl-nt3-5555C9D0E1F2"
],
"timestamp": "2025-08-03T10:00:00+00:00",
"aggregation": "15min"
}
Request Parameters
| Field | Type | Required | Description |
|---|---|---|---|
| deviceIds | array | Yes | Array of device IDs (1-150 devices) |
| timestamp | ISO 8601 | Yes | Start time (must be within last 24 hours) |
| aggregation | string | No | "none" or "15min" (default: 15min) |
Example Request
curl -X POST \
https://api.enpact.iote.uk/api/v1/devices/batch/data \
-H 'X-API-Key: your-64-character-api-key' \
-H 'Content-Type: application/json' \
-d '{
"deviceIds": [
"esl-nt3-5555A1B2C3D4",
"esl-nt3-5555E5F6A7B8"
],
"timestamp": "2025-08-03T10:00:00+00:00",
"aggregation": "15min"
}'
POST Query Endpoint (Simplified)
/api/v1/query
A simplified endpoint for querying device data. Functionally identical to the batch endpoint but with a cleaner URL. Returns 15 minutes of data for the specified devices starting from the timestamp.
Request Body
{
"deviceIds": [
"esl-nt3-5555A1B2C3D4",
"esl-nt3-5555E5F6A7B8"
],
"timestamp": "2025-08-03T10:00:00+00:00",
"aggregation": "none"
}
Example Request
curl -X POST \
https://api.enpact.iote.uk/api/v1/query \
-H 'X-API-Key: your-64-character-api-key' \
-H 'Content-Type: application/json' \
-d '{
"deviceIds": ["esl-nt3-5555A1B2C3D4"],
"timestamp": "2025-08-03T10:00:00+00:00",
"aggregation": "none"
}'
Data Formats
The API returns temperature data and energy saver status for cooling devices. Data can be returned as raw measurements (every 30 seconds) or aggregated over the 15-minute window.
Raw Data Response (aggregation=none)
Returns 30 data points, one every 30 seconds for the 15-minute window.
{
"data": {
"esl-nt3-5555A1B2C3D4": [
{
"timestamp": "2025-08-03T10:00:00+00:00",
"coolantIn": 1.2,
"coolantOut": 2.1,
"space": 4.8,
"cpuTemp": 32.5,
"compressorEnergySaverEnabled": false,
"fanEnergySaverEnabled": true
},
{
"timestamp": "2025-08-03T10:00:30+00:00",
"coolantIn": 1.3,
"coolantOut": 2.2,
"space": 4.9,
"cpuTemp": 32.8,
"compressorEnergySaverEnabled": false,
"fanEnergySaverEnabled": true
}
]
},
"meta": {
"timestamp": "2025-08-03T10:00:00+00:00",
"window": "15min",
"aggregation": "none",
"device_count": 1,
"units": {
"coolantIn": "°C",
"coolantOut": "°C",
"space": "°C",
"cpuTemp": "°C"
}
}
}
Aggregated Data Response (aggregation=15min)
Returns statistical summary of the 15-minute window.
{
"data": {
"esl-nt3-5555A1B2C3D4": [
{
"timestamp": "2025-08-03T10:00:00+00:00",
"period": "15min",
"coolantIn": {
"avg": 1.2,
"min": 0.8,
"max": 1.5,
"unit": "°C"
},
"coolantOut": {
"avg": 2.2,
"min": 1.9,
"max": 2.5,
"unit": "°C"
},
"space": {
"avg": 5.0,
"min": 4.2,
"max": 5.8,
"unit": "°C"
},
"cpuTemp": {
"avg": 32.5,
"min": 28.0,
"max": 38.0,
"unit": "°C"
},
"compressorEnergySaverEnabled": {
"percentTrue": 20
},
"fanEnergySaverEnabled": {
"percentTrue": 80
}
}
]
},
"meta": {
"timestamp": "2025-08-03T10:00:00+00:00",
"window": "15min",
"aggregation": "15min",
"device_count": 1
}
}
Data Fields
| Field | Type | Range | Description |
|---|---|---|---|
| coolantIn | float | 0.8 - 1.5 °C | Coolant inlet temperature |
| coolantOut | float | 1.9 - 2.5 °C | Coolant outlet temperature |
| space | float | 4.2 - 5.8 °C | Space/ambient temperature |
| cpuTemp | float | 28.0 - 38.0 °C | CPU temperature |
| compressorEnergySaverEnabled | boolean (raw) / percentage (aggregated) | true/false or 0-100% | Compressor energy saver status |
| fanEnergySaverEnabled | boolean (raw) / percentage (aggregated) | true/false or 0-100% | Fan energy saver status |
Meter Data Fields
Meter endpoints return electrical measurement data. The available fields depend on the meter type: single-phase meters provide basic current measurements, three-phase meters include all three phases, and advanced meters provide comprehensive electrical data including voltage, power, and energy measurements.
| Field | Type | Unit | Range | Nullable | Description |
|---|---|---|---|---|---|
| Common Fields (All Meter Types) | |||||
| timestamp | string | - | ISO 8601 | No | Measurement timestamp |
| deviceName | string | - | 1-50 chars | No | Human-readable device name |
| gwId | string | - | 1-20 chars | No | Gateway identifier |
| fault | string | - | "true"/"false" | No | Fault status indicator |
| expiry | integer | ms | Unix timestamp | No | Data expiry timestamp (milliseconds) |
| Current Measurements | |||||
| c1 | float | A | 0.0 - 50.0 | No | Phase 1 current (all meter types) |
| c2 | float | A | 0.0 - 50.0 | Yes | Phase 2 current (three-phase and advanced only) |
| c3 | float | A | 0.0 - 50.0 | Yes | Phase 3 current (three-phase and advanced only) |
| Voltage Measurements (Advanced Meters Only) | |||||
| v1 | float | V | 200.0 - 250.0 | Yes | Phase 1 voltage |
| v2 | float | V | 200.0 - 250.0 | Yes | Phase 2 voltage |
| v3 | float | V | 200.0 - 250.0 | Yes | Phase 3 voltage |
| Power Measurements (Advanced Meters Only) | |||||
| p1 | float | W | 0.0 - 5000.0 | Yes | Phase 1 active power |
| p2 | float | W | 0.0 - 5000.0 | Yes | Phase 2 active power |
| p3 | float | W | 0.0 - 5000.0 | Yes | Phase 3 active power |
| pf1 | float | - | 0.0 - 1.0 | Yes | Phase 1 power factor |
| pf2 | float | - | 0.0 - 1.0 | Yes | Phase 2 power factor |
| pf3 | float | - | 0.0 - 1.0 | Yes | Phase 3 power factor |
| System Measurements (Advanced Meters Only) | |||||
| freq | float | Hz | 49.0 - 51.0 | Yes | Line frequency |
| imp | float | kWh | 0.0 - 999999.9 | Yes | Cumulative import energy |
| exp | float | kWh | 0.0 - 999999.9 | Yes | Cumulative export energy |
Meter Type Field Availability
- Single-Phase Meters: Common fields + c1 only (c2, c3 are null)
- Three-Phase Meters: Common fields + c1, c2, c3 (voltage/power fields are null)
- Advanced Meters: All fields available (comprehensive electrical measurements)
Meter Raw Data Response Example
Raw meter data (aggregation=none) returns 30 data points, one every 30 seconds for the 15-minute window. This example shows data from an advanced meter with all available fields.
{
"data": {
"meter-advanced-007": [
{
"timestamp": "2025-08-03T10:00:00+00:00",
"deviceName": "Advanced Energy Meter",
"gwId": "pgw-nec1",
"fault": "false",
"expiry": 1735689600000,
"c1": 15.2,
"c2": 14.8,
"c3": 15.1,
"v1": 230.5,
"v2": 229.8,
"v3": 231.2,
"p1": 3486,
"p2": 3395,
"p3": 3512,
"pf1": 0.95,
"pf2": 0.94,
"pf3": 0.96,
"freq": 50.0,
"imp": 1234.5,
"exp": 0.0
},
{
"timestamp": "2025-08-03T10:00:30+00:00",
"deviceName": "Advanced Energy Meter",
"gwId": "pgw-nec1",
"fault": "false",
"expiry": 1735689600000,
"c1": 15.3,
"c2": 14.9,
"c3": 15.0,
"v1": 230.8,
"v2": 230.1,
"v3": 231.0,
"p1": 3501,
"p2": 3410,
"p3": 3498,
"pf1": 0.96,
"pf2": 0.95,
"pf3": 0.95,
"freq": 50.1,
"imp": 1234.6,
"exp": 0.0
},
{
"timestamp": "2025-08-03T10:01:00+00:00",
"deviceName": "Advanced Energy Meter",
"gwId": "pgw-nec1",
"fault": "false",
"expiry": 1735689600000,
"c1": 15.0,
"c2": 14.7,
"c3": 14.9,
"v1": 230.2,
"v2": 229.5,
"v3": 230.8,
"p1": 3465,
"p2": 3380,
"p3": 3485,
"pf1": 0.94,
"pf2": 0.93,
"pf3": 0.94,
"freq": 49.9,
"imp": 1234.7,
"exp": 0.1
}
]
},
"meta": {
"timestamp": "2025-08-03T10:00:00+00:00",
"window": "15min",
"aggregation": "none",
"meter_count": 1,
"units": {
"c1": "A", "c2": "A", "c3": "A",
"v1": "V", "v2": "V", "v3": "V",
"p1": "W", "p2": "W", "p3": "W",
"pf1": "", "pf2": "", "pf3": "",
"freq": "Hz", "imp": "kWh", "exp": "kWh"
}
}
}
Single-Phase Meter Raw Data Example
Single-phase meters only provide c1 current measurements, with c2 and c3 as null.
{
"data": {
"meter-single-001": [
{
"timestamp": "2025-08-03T10:00:00+00:00",
"deviceName": "Single Phase Meter",
"gwId": "pgw-nec1",
"fault": "false",
"expiry": 1735689600000,
"c1": 12.5,
"c2": null,
"c3": null
},
{
"timestamp": "2025-08-03T10:00:30+00:00",
"deviceName": "Single Phase Meter",
"gwId": "pgw-nec1",
"fault": "false",
"expiry": 1735689600000,
"c1": 12.7,
"c2": null,
"c3": null
}
]
},
"meta": {
"timestamp": "2025-08-03T10:00:00+00:00",
"window": "15min",
"aggregation": "none",
"meter_count": 1,
"units": {
"c1": "A"
}
}
}
Three-Phase Meter Raw Data Example
Three-phase meters provide c1, c2, and c3 current measurements but no voltage or power data.
{
"data": {
"meter-three-004": [
{
"timestamp": "2025-08-03T10:00:00+00:00",
"deviceName": "Three Phase Meter",
"gwId": "pgw-nec2",
"fault": "false",
"expiry": 1735689600000,
"c1": 18.2,
"c2": 17.8,
"c3": 18.0
},
{
"timestamp": "2025-08-03T10:00:30+00:00",
"deviceName": "Three Phase Meter",
"gwId": "pgw-nec2",
"fault": "false",
"expiry": 1735689600000,
"c1": 18.4,
"c2": 17.9,
"c3": 18.1
}
]
},
"meta": {
"timestamp": "2025-08-03T10:00:00+00:00",
"window": "15min",
"aggregation": "none",
"meter_count": 1,
"units": {
"c1": "A", "c2": "A", "c3": "A"
}
}
}
Meter Aggregated Data Response Example
Aggregated meter data (aggregation=15min) returns statistical summaries of the 15-minute window. Numeric fields show average, minimum, and maximum values with their units.
Advanced Meter Aggregated Data
{
"data": {
"meter-advanced-007": [
{
"timestamp": "2025-08-03T10:00:00+00:00",
"period": "15min",
"deviceName": "Advanced Energy Meter",
"gwId": "pgw-nec1",
"fault": "false",
"expiry": 1735689600000,
"c1": {
"avg": 15.1,
"min": 14.8,
"max": 15.4,
"unit": "A"
},
"c2": {
"avg": 14.9,
"min": 14.6,
"max": 15.2,
"unit": "A"
},
"c3": {
"avg": 15.0,
"min": 14.7,
"max": 15.3,
"unit": "A"
},
"v1": {
"avg": 230.6,
"min": 229.8,
"max": 231.4,
"unit": "V"
},
"v2": {
"avg": 230.0,
"min": 229.2,
"max": 230.8,
"unit": "V"
},
"v3": {
"avg": 231.1,
"min": 230.3,
"max": 231.9,
"unit": "V"
},
"p1": {
"avg": 3495,
"min": 3420,
"max": 3570,
"unit": "W"
},
"p2": {
"avg": 3402,
"min": 3330,
"max": 3474,
"unit": "W"
},
"p3": {
"avg": 3505,
"min": 3435,
"max": 3575,
"unit": "W"
},
"pf1": {
"avg": 0.95,
"min": 0.93,
"max": 0.97,
"unit": ""
},
"pf2": {
"avg": 0.94,
"min": 0.92,
"max": 0.96,
"unit": ""
},
"pf3": {
"avg": 0.95,
"min": 0.93,
"max": 0.97,
"unit": ""
},
"freq": {
"avg": 50.0,
"min": 49.9,
"max": 50.1,
"unit": "Hz"
},
"imp": {
"avg": 1234.8,
"min": 1234.5,
"max": 1235.1,
"unit": "kWh"
},
"exp": {
"avg": 0.1,
"min": 0.0,
"max": 0.2,
"unit": "kWh"
}
}
]
},
"meta": {
"timestamp": "2025-08-03T10:00:00+00:00",
"window": "15min",
"aggregation": "15min",
"meter_count": 1
}
}
Single-Phase Meter Aggregated Data
Single-phase meters show aggregated statistics for c1 only, with c2 and c3 as null.
{
"data": {
"meter-single-001": [
{
"timestamp": "2025-08-03T10:00:00+00:00",
"period": "15min",
"deviceName": "Single Phase Meter",
"gwId": "pgw-nec1",
"fault": "false",
"expiry": 1735689600000,
"c1": {
"avg": 12.5,
"min": 11.8,
"max": 13.2,
"unit": "A"
},
"c2": null,
"c3": null
}
]
},
"meta": {
"timestamp": "2025-08-03T10:00:00+00:00",
"window": "15min",
"aggregation": "15min",
"meter_count": 1
}
}
Three-Phase Meter Aggregated Data
Three-phase meters provide aggregated statistics for all three current phases.
{
"data": {
"meter-three-004": [
{
"timestamp": "2025-08-03T10:00:00+00:00",
"period": "15min",
"deviceName": "Three Phase Meter",
"gwId": "pgw-nec2",
"fault": "false",
"expiry": 1735689600000,
"c1": {
"avg": 18.2,
"min": 17.5,
"max": 18.9,
"unit": "A"
},
"c2": {
"avg": 17.8,
"min": 17.1,
"max": 18.5,
"unit": "A"
},
"c3": {
"avg": 18.0,
"min": 17.3,
"max": 18.7,
"unit": "A"
}
}
]
},
"meta": {
"timestamp": "2025-08-03T10:00:00+00:00",
"window": "15min",
"aggregation": "15min",
"meter_count": 1
}
}
Aggregation Notes
- Statistical Fields: All numeric measurements include avg, min, max, and unit
- String Fields: deviceName, gwId, fault, and expiry remain as single values
- Null Fields: Fields not available for a meter type remain null in aggregated data
- Energy Fields: Import/export energy (imp/exp) show cumulative values over the period
Error Handling
The API uses standard HTTP status codes and provides detailed error messages to help diagnose issues.
Error Response Structure
{
"error": "Bad Request",
"message": "Invalid parameters.",
"errors": {
"timestamp": ["The timestamp field is required."]
}
}
HTTP Status Codes
| Status Code | Description | Common Scenarios |
|---|---|---|
| 200 | Success - Request completed successfully | Data retrieved successfully, even if some devices/meters return empty data |
| 400 | Bad Request - Invalid request parameters | Missing required fields, invalid timestamp format, timestamp outside 24-hour window, invalid aggregation value, malformed JSON |
| 401 | Unauthorized - Authentication failed | Missing X-API-Key header, invalid API key format, expired API key, revoked API key |
| 403 | Forbidden - Access denied | Device/meter not in whitelist, sandbox key used in production, production key used in sandbox, invalid test device/meter IDs |
| 422 | Unprocessable Entity - Validation failed | Field validation errors, too many device/meter IDs (>150), empty device/meter ID arrays |
| 429 | Too Many Requests - Rate limit exceeded | Exceeded 300 req/15min (production) or 30 req/sec (sandbox), includes rate limit headers |
| 500 | Internal Server Error - Unexpected server error | Database connection issues, DynamoDB service errors, unexpected application errors |
| 503 | Service Unavailable - Service temporarily unavailable | Maintenance mode, external service dependencies unavailable |
Detailed Error Response Examples
Authentication Errors (401)
Missing API Key
{
"error": "Unauthorized",
"message": "API key is required. Please include X-API-Key header."
}
Invalid API Key Format
{
"error": "Unauthorized",
"message": "Invalid API key format. API key must be 64 characters long."
}
Expired or Invalid API Key
{
"error": "Unauthorized",
"message": "Invalid or expired API key."
}
Field Validation Errors (400)
Missing Required Fields
{
"error": "Bad Request",
"message": "Invalid parameters.",
"errors": {
"timestamp": ["The timestamp field is required."],
"deviceIds": ["The device ids field is required."]
}
}
Invalid Timestamp Format
{
"error": "Bad Request",
"message": "Invalid parameters.",
"errors": {
"timestamp": ["The timestamp does not match the format Y-m-d\\TH:i:s\\Z."]
}
}
Timestamp Out of Range
{
"error": "Bad Request",
"message": "Timestamp must be within the last 24 hours."
}
Too Many Device/Meter IDs
{
"error": "Bad Request",
"message": "Invalid parameters.",
"errors": {
"deviceIds": ["The device ids may not have more than 150 items."]
}
}
Invalid Aggregation Value
{
"error": "Bad Request",
"message": "Invalid parameters.",
"errors": {
"aggregation": ["The selected aggregation is invalid. Must be 'none' or '15min'."]
}
}
Access Control Errors (403)
Device Not Whitelisted (Production)
{
"error": "Forbidden",
"message": "Access denied for devices: esl-nt3-unauthorized-device",
"unauthorized_devices": ["esl-nt3-unauthorized-device"]
}
Meter Not Whitelisted (Production)
{
"error": "Forbidden",
"message": "Access denied for meters: meter-unauthorized-001",
"unauthorized_meters": ["meter-unauthorized-001"]
}
Invalid Sandbox Test Device
{
"error": "Forbidden",
"message": "Invalid sandbox test devices: invalid-test-device",
"unauthorized_devices": ["invalid-test-device"],
"allowed_devices": [
"esl-nt3-test-device-001",
"esl-nt3-test-device-002",
"esl-nt3-test-device-003",
"esl-nt3-test-device-004",
"esl-nt3-test-device-005"
]
}
Invalid Sandbox Test Meter
{
"error": "Forbidden",
"message": "Invalid sandbox test meters: invalid-test-meter",
"unauthorized_meters": ["invalid-test-meter"],
"allowed_meters": [
"meter-test-building-a-001",
"meter-test-building-a-002",
"meter-test-building-b-001"
]
}
Rate Limit Errors (429)
Production Rate Limit Exceeded
{
"error": "Too Many Requests",
"message": "Rate limit exceeded. Maximum 300 requests per 15 minutes.",
"retry_after": 847
}
Response includes rate limit headers:
X-RateLimit-Limit: 300
X-RateLimit-Remaining: 0
X-RateLimit-Reset: 1704124800
X-RateLimit-Window: 15m
Sandbox Rate Limit Exceeded
{
"error": "Too Many Requests",
"message": "Rate limit exceeded. Maximum 30 requests per second.",
"retry_after": 1
}
Response includes rate limit headers:
X-RateLimit-Limit: 30
X-RateLimit-Remaining: 0
X-RateLimit-Reset: 1704124801
X-RateLimit-Window: 1s
Server Errors (500)
Internal Server Error
{
"error": "Internal Server Error",
"message": "An unexpected error occurred. Please try again later."
}
Service Unavailable
{
"error": "Service Unavailable",
"message": "The service is temporarily unavailable. Please try again later."
}
Environment-Specific Error Scenarios
Environment Key Mismatch Errors
Sandbox Key Used in Production
When a sandbox API key is used to access production endpoints (api.enpact.iote.uk):
{
"error": "Forbidden",
"message": "Sandbox API keys cannot access production environment. Please use a production API key or switch to sandbox endpoints."
}
Production Key Used in Sandbox
When a production API key is used to access sandbox endpoints (sandbox-api.enpact.iote.uk):
{
"error": "Forbidden",
"message": "Production API keys cannot access sandbox environment. Please use a sandbox API key or switch to production endpoints."
}
Environment Detection
The API automatically detects the environment based on the hostname. Ensure you're using the correct base URL:
- • Production: https://api.enpact.iote.uk/api/v1
- • Sandbox: https://sandbox-api.enpact.iote.uk/api/v1
Whitelist Configuration Errors
Production Device Not Whitelisted
When requesting access to a device that hasn't been added to your production whitelist:
{
"error": "Forbidden",
"message": "Access denied for devices: esl-nt3-5555A1B2C3D4, esl-nt3-5555E5F6A7B8",
"unauthorized_devices": [
"esl-nt3-5555A1B2C3D4",
"esl-nt3-5555E5F6A7B8"
]
}
Solution: Contact your administrator to add these devices to your production whitelist.
Production Meter Not Whitelisted
When requesting access to a meter that hasn't been added to your production whitelist:
{
"error": "Forbidden",
"message": "Access denied for meters: meter-building-c-001",
"unauthorized_meters": ["meter-building-c-001"]
}
Solution: Contact your administrator to add these meters to your production whitelist.
Invalid Sandbox Test IDs
When using device or meter IDs that don't exist in the sandbox test data:
{
"error": "Forbidden",
"message": "Invalid sandbox test devices: custom-device-001",
"unauthorized_devices": ["custom-device-001"],
"allowed_devices": [
"esl-nt3-test-device-001",
"esl-nt3-test-device-002",
"esl-nt3-test-device-003",
"esl-nt3-test-device-004",
"esl-nt3-test-device-005"
]
}
Note: Sandbox environments only accept predefined test IDs. Use the provided test IDs for development and testing.
Mixed Environment Access
When trying to access both sandbox and production resources in the same request:
{
"error": "Bad Request",
"message": "Cannot mix sandbox test IDs with production device IDs in the same request.",
"details": "Use either sandbox test IDs or production device IDs, not both."
}
Environment-Specific Rate Limit Behavior
Production Rate Limit Context
Production rate limits are shared across all endpoints (devices and meters) for your API key:
{
"error": "Too Many Requests",
"message": "Rate limit exceeded. Maximum 300 requests per 15 minutes across all endpoints.",
"retry_after": 847,
"rate_limit_scope": "all_endpoints"
}
Sandbox Rate Limit Context
Sandbox rate limits are also shared but reset every second:
{
"error": "Too Many Requests",
"message": "Rate limit exceeded. Maximum 30 requests per second across all endpoints.",
"retry_after": 1,
"rate_limit_scope": "all_endpoints"
}
Meter Endpoints
The IoT Edge API provides endpoints for retrieving electrical meter data including current, voltage, power, and energy measurements. All data is returned for a 15-minute window starting from the specified timestamp.
GET List Meters
/api/v1/meters
Retrieve a list of all available meter IDs that are accessible with your API key. This endpoint returns only the meter IDs that are whitelisted for your API key.
Example Request
curl -X GET \
https://api.enpact.iote.uk/api/v1/meters \
-H 'X-API-Key: your-64-character-api-key'
Example Response (Production)
{
"meters": [
"meter-building-a-001",
"meter-building-a-002",
"meter-building-b-001"
],
"meta": {
"count": 3,
"environment": "production"
}
}
Example Response (Sandbox)
{
"meters": [
"meter-single-001",
"meter-single-002",
"meter-three-004",
"meter-three-005",
"meter-advanced-007",
"iemtr-sdm-test001"
],
"meta": {
"count": 6,
"environment": "sandbox"
}
}
Note: In sandbox environment, this endpoint returns predefined test meter IDs. In production, it returns only the meters whitelisted for your API key.
GET Get Meter Data
/api/v1/meters/{meterId}/data
Retrieve data for a single meter. Returns 15 minutes of electrical measurements starting from the specified timestamp.
Path Parameters
| Parameter | Type | Description |
|---|---|---|
| meterId | string | Unique identifier of the meter |
Query Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
| timestamp | ISO 8601 | Yes | Start time (format: Y-m-d\TH:i:s\Z). Must be within last 24 hours |
| aggregation | string | No | "none" for raw data or "15min" for aggregated (default: 15min) |
Example Request
curl -X GET \
'https://api.enpact.iote.uk/api/v1/meters/meter-advanced-007/data?timestamp=2025-08-03T10:00:00+00:00&aggregation=none' \
-H 'X-API-Key: your-64-character-api-key'
Example Response (Raw Data)
{
"data": {
"meter-advanced-007": [
{
"timestamp": "2025-08-03T10:00:00+00:00",
"deviceName": "Advanced Energy Meter",
"gwId": "pgw-nec1",
"fault": "false",
"expiry": 1735689600000,
"c1": 15.2,
"c2": 14.8,
"c3": 15.1,
"v1": 230.5,
"v2": 229.8,
"v3": 231.2,
"p1": 3486,
"p2": 3395,
"p3": 3512,
"pf1": 0.95,
"pf2": 0.94,
"pf3": 0.96,
"freq": 50.0,
"imp": 1234.5,
"exp": 0.0
},
{
"timestamp": "2025-08-03T10:00:30+00:00",
"deviceName": "Advanced Energy Meter",
"gwId": "pgw-nec1",
"fault": "false",
"expiry": 1735689600000,
"c1": 15.3,
"c2": 14.9,
"c3": 15.0,
"v1": 230.8,
"v2": 230.1,
"v3": 231.0,
"p1": 3501,
"p2": 3410,
"p3": 3498,
"pf1": 0.96,
"pf2": 0.95,
"pf3": 0.95,
"freq": 50.1,
"imp": 1234.6,
"exp": 0.0
}
]
},
"meta": {
"timestamp": "2025-08-03T10:00:00+00:00",
"window": "15min",
"aggregation": "none",
"meter_count": 1,
"units": {
"c1": "A", "c2": "A", "c3": "A",
"v1": "V", "v2": "V", "v3": "V",
"p1": "W", "p2": "W", "p3": "W",
"pf1": "", "pf2": "", "pf3": "",
"freq": "Hz", "imp": "kWh", "exp": "kWh"
}
}
}
Example Response (Aggregated Data)
{
"data": {
"meter-advanced-007": [
{
"timestamp": "2025-08-03T10:00:00+00:00",
"period": "15min",
"deviceName": "Advanced Energy Meter",
"gwId": "pgw-nec1",
"fault": "false",
"expiry": 1735689600000,
"c1": {
"avg": 15.1,
"min": 14.8,
"max": 15.4,
"unit": "A"
},
"c2": {
"avg": 14.9,
"min": 14.6,
"max": 15.2,
"unit": "A"
},
"c3": {
"avg": 15.0,
"min": 14.7,
"max": 15.3,
"unit": "A"
},
"v1": {
"avg": 230.6,
"min": 229.8,
"max": 231.4,
"unit": "V"
},
"v2": {
"avg": 230.0,
"min": 229.2,
"max": 230.8,
"unit": "V"
},
"v3": {
"avg": 231.1,
"min": 230.3,
"max": 231.9,
"unit": "V"
},
"p1": {
"avg": 3495,
"min": 3420,
"max": 3570,
"unit": "W"
},
"p2": {
"avg": 3402,
"min": 3330,
"max": 3474,
"unit": "W"
},
"p3": {
"avg": 3505,
"min": 3435,
"max": 3575,
"unit": "W"
},
"pf1": {
"avg": 0.95,
"min": 0.93,
"max": 0.97,
"unit": ""
},
"pf2": {
"avg": 0.94,
"min": 0.92,
"max": 0.96,
"unit": ""
},
"pf3": {
"avg": 0.95,
"min": 0.93,
"max": 0.97,
"unit": ""
},
"freq": {
"avg": 50.0,
"min": 49.9,
"max": 50.1,
"unit": "Hz"
},
"imp": {
"avg": 1234.8,
"min": 1234.5,
"max": 1235.1,
"unit": "kWh"
},
"exp": {
"avg": 0.1,
"min": 0.0,
"max": 0.2,
"unit": "kWh"
}
}
]
},
"meta": {
"timestamp": "2025-08-03T10:00:00+00:00",
"window": "15min",
"aggregation": "15min",
"meter_count": 1
}
}
POST Batch Meter Data
/api/v1/meters/batch/data
Retrieve data for multiple meters in a single request. Returns 15 minutes of electrical measurements for each meter starting from the specified timestamp. Maximum 150 meters per request.
Request Body
{
"meterIds": [
"meter-single-001",
"meter-three-004",
"meter-advanced-007"
],
"timestamp": "2025-08-03T10:00:00+00:00",
"aggregation": "15min"
}
Request Parameters
| Field | Type | Required | Description |
|---|---|---|---|
| meterIds | array | Yes | Array of meter IDs (1-150 meters) |
| timestamp | ISO 8601 | Yes | Start time (must be within last 24 hours) |
| aggregation | string | No | "none" or "15min" (default: 15min) |
Example Request
curl -X POST \
https://api.enpact.iote.uk/api/v1/meters/batch/data \
-H 'X-API-Key: your-64-character-api-key' \
-H 'Content-Type: application/json' \
-d '{
"meterIds": [
"meter-single-001",
"meter-three-004",
"meter-advanced-007"
],
"timestamp": "2025-08-03T10:00:00+00:00",
"aggregation": "15min"
}'
Example Response
{
"data": {
"meter-single-001": [
{
"timestamp": "2025-08-03T10:00:00+00:00",
"period": "15min",
"deviceName": "Single Phase Meter",
"gwId": "pgw-nec1",
"fault": "false",
"expiry": 1735689600000,
"c1": {
"avg": 12.5,
"min": 11.8,
"max": 13.2,
"unit": "A"
},
"c2": null,
"c3": null
}
],
"meter-three-004": [
{
"timestamp": "2025-08-03T10:00:00+00:00",
"period": "15min",
"deviceName": "Three Phase Meter",
"gwId": "pgw-nec2",
"fault": "false",
"expiry": 1735689600000,
"c1": {
"avg": 18.2,
"min": 17.5,
"max": 18.9,
"unit": "A"
},
"c2": {
"avg": 17.8,
"min": 17.1,
"max": 18.5,
"unit": "A"
},
"c3": {
"avg": 18.0,
"min": 17.3,
"max": 18.7,
"unit": "A"
}
}
],
"meter-advanced-007": [
{
"timestamp": "2025-08-03T10:00:00+00:00",
"period": "15min",
"deviceName": "Advanced Energy Meter",
"gwId": "pgw-nec1",
"fault": "false",
"expiry": 1735689600000,
"c1": {
"avg": 15.1,
"min": 14.8,
"max": 15.4,
"unit": "A"
},
"c2": {
"avg": 14.9,
"min": 14.6,
"max": 15.2,
"unit": "A"
},
"c3": {
"avg": 15.0,
"min": 14.7,
"max": 15.3,
"unit": "A"
},
"v1": {
"avg": 230.6,
"min": 229.8,
"max": 231.4,
"unit": "V"
},
"v2": {
"avg": 230.0,
"min": 229.2,
"max": 230.8,
"unit": "V"
},
"v3": {
"avg": 231.1,
"min": 230.3,
"max": 231.9,
"unit": "V"
},
"p1": {
"avg": 3495,
"min": 3420,
"max": 3570,
"unit": "W"
},
"p2": {
"avg": 3402,
"min": 3330,
"max": 3474,
"unit": "W"
},
"p3": {
"avg": 3505,
"min": 3435,
"max": 3575,
"unit": "W"
},
"pf1": {
"avg": 0.95,
"min": 0.93,
"max": 0.97,
"unit": ""
},
"pf2": {
"avg": 0.94,
"min": 0.92,
"max": 0.96,
"unit": ""
},
"pf3": {
"avg": 0.95,
"min": 0.93,
"max": 0.97,
"unit": ""
},
"freq": {
"avg": 50.0,
"min": 49.9,
"max": 50.1,
"unit": "Hz"
},
"imp": {
"avg": 1234.8,
"min": 1234.5,
"max": 1235.1,
"unit": "kWh"
},
"exp": {
"avg": 0.1,
"min": 0.0,
"max": 0.2,
"unit": "kWh"
}
}
]
},
"meta": {
"timestamp": "2025-08-03T10:00:00+00:00",
"window": "15min",
"aggregation": "15min",
"meter_count": 3
}
}
Note: Different meter types return different data fields. Single-phase meters only have c1, three-phase meters have c1-c3, and advanced meters include voltage, power, frequency, and energy data.
GET Health Check
/api/v1/health
Simple health check endpoint to verify API availability. This endpoint does not require authentication and can be used for monitoring and uptime checks.
Example Request
curl -X GET \
https://api.enpact.iote.uk/api/v1/health
Example Response
{
"status": "ok",
"timestamp": "2025-08-03T10:00:00+00:00"
}
Usage: This endpoint is useful for monitoring, load balancer health checks, and verifying API availability. No authentication is required.
Rate Limits
Rate limits are enforced based on API key and environment to ensure fair usage and system stability. The same rate limits apply to all endpoints (devices, meters, health check, etc.) within each environment.
Environment-Specific Limits
Production
Unified rate limit for all endpoints
Sandbox
Unified rate limit for all endpoints
Rate Limit Headers
Every API response includes headers with rate limit information:
# Production environment headers
X-RateLimit-Limit: 300 # Maximum requests allowed
X-RateLimit-Remaining: 299 # Requests remaining in window
X-RateLimit-Reset: 1704124800 # Unix timestamp when limit resets
X-RateLimit-Window: 15m # Time window (15m for production)
# Sandbox environment headers
X-RateLimit-Limit: 30 # Maximum requests allowed
X-RateLimit-Remaining: 29 # Requests remaining in window
X-RateLimit-Reset: 1704124801 # Unix timestamp when limit resets
X-RateLimit-Window: 1s # Time window (1s for sandbox)
Best Practice: Monitor the X-RateLimit-Remaining
header and implement exponential backoff when approaching limits.
Test Data
The following device and meter IDs are available for testing in the sandbox environment. These generate consistent mock data based on the ID and timestamp for predictable testing scenarios.
Available Test Device IDs
Test devices simulate cooling equipment with temperature sensors and energy saver controls. All devices return the same data fields but with unique values based on the device ID.
Device Data Fields
- • coolantIn: Coolant inlet temperature (0.8-1.5°C)
- • coolantOut: Coolant outlet temperature (1.9-2.5°C)
- • space: Space temperature (4.2-5.8°C)
- • cpuTemp: CPU temperature (28.0-38.0°C)
- • compressorEnergySaverEnabled: Compressor energy saver status (boolean)
- • fanEnergySaverEnabled: Fan energy saver status (boolean)
Available Test Meter IDs
Test meters are categorized by type based on their ID pattern. Each type returns different data fields to simulate various meter configurations.
Single-Phase Meters (IDs ending in 1-3)
Returns: c1 (current), deviceName, gwId, fault, expiry
Three-Phase Meters (IDs ending in 4-6)
Returns: c1, c2, c3 (three-phase current), deviceName, gwId, fault, expiry
Advanced Energy Meters (IDs ending in 7-9 or containing 'iemtr')
Returns: All fields including c1-c3, v1-v3, p1-p3, pf1-pf3, freq, imp, exp
Deterministic Mock Data Generation
Mock data is deterministic and seeded using the device/meter ID and timestamp. The same ID and timestamp combination will always return identical data, making testing repeatable and predictable.
- • Consistent Results: Same request parameters always return the same data
- • Realistic Values: Generated data falls within typical operational ranges
- • Time-based Variation: Different timestamps produce different but consistent values
- • ID-based Seeding: Each meter/device ID has its own data pattern
Example Sandbox Requests
Device Data Request
curl -X GET \
'https://sandbox-api.enpact.iote.uk/api/v1/devices/esl-nt3-5555A1B2C3D4/data?timestamp=2025-08-03T10:00:00+00:00' \
-H 'X-API-Key: your-sandbox-api-key-here'
Single Meter Data Request
curl -X GET \
'https://sandbox-api.enpact.iote.uk/api/v1/meters/meter-single-001/data?timestamp=2025-08-03T10:00:00+00:00&aggregation=15min' \
-H 'X-API-Key: your-sandbox-api-key-here'
Advanced Energy Meter Request (Raw Data)
curl -X GET \
'https://sandbox-api.enpact.iote.uk/api/v1/meters/iemtr-sdm-test001/data?timestamp=2025-08-03T10:00:00+00:00&aggregation=none' \
-H 'X-API-Key: your-sandbox-api-key-here'