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

300 requests
per 15 minutes

Unified rate limit for all endpoints

Sandbox

30 requests
per second

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.

esl-nt3-5555A1B2C3D4
esl-nt3-5555E5F6A7B8
esl-nt3-5555C9D0E1F2
esl-nt3-555503040506
esl-nt3-5555AABBCCDD
esl-nt3-5555DEADBEEF
esl-nt3-555512345678
esl-nt3-5555F0F1F2F3
esl-nt3-555587654321
esl-nt3-5555CAFEBABE

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)

meter-single-001
meter-single-002
meter-single-003

Returns: c1 (current), deviceName, gwId, fault, expiry

Three-Phase Meters (IDs ending in 4-6)

meter-three-004
meter-three-005
meter-three-006

Returns: c1, c2, c3 (three-phase current), deviceName, gwId, fault, expiry

Advanced Energy Meters (IDs ending in 7-9 or containing 'iemtr')

meter-advanced-007
meter-advanced-008
meter-advanced-009
iemtr-sdm-test001

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'