Hydrotwin External API

Hydrotwin External API



Authentication

Every request must include your API key in the X-API-Key header.
X-API-Key: ht_org_your_key_here
Your key is issued when your organisation is created. It starts with ht_org_ and is only shown once — store it securely. If you lose it or it is compromised, contact the Hydrotwin team to rotate it.
Key rotation — when a key is rotated your old key stays valid for 24 hours so you have time to update your systems without downtime.
Rate limit — The API has a limit of 500 requests per hour


Base URL

https://api.hydrotwin.ai


1. Setup



GET /v1/status

Verify your API key is working and inspect your granted scopes.
Request
GET /api/v1/status
X-API-Key: ht_org_abc123...
Response
{
"ok": true,
"auth_type": "api_key",
"org_id": "<ORGID>",
"scopes": [
"deployments:read",
"measurements:read"
]
}


GET /deployments

List all Hydrotwin deployments your organisation has been granted access to.
Scope required: deployments:read
Request
GET /api/deployments
X-API-Key: ht_org_abc123...
Response
{
"deployments": [
{
"id": 12,
"ht_id": "HT-S-001",
"location": "Lagos Harbour",
"client": "Nigerian Ports Authority",
"intervention_at": "2025-01-15T08:00:00.000Z"
},
{
"id": 17,
"ht_id": "HT-C-004",
"location": "Lagos Harbour",
"client": "Nigerian Ports Authority",
"intervention_at": "2025-03-01T10:30:00.000Z"
}
]
}


GET /hydrotwins

List all Hydrotwins accessible to your organisation, grouped by HT ID with active status and GPS coordinates. Use this to discover which hydrotwin_id values to use in measurement endpoints.
Scope required: measurements:read
Request
GET /api/hydrotwins
X-API-Key: ht_org_abc123...
Response
{
"hydrotwins": [
{
"htId": "HT-S-001",
"client": "Nigerian Ports Authority",
"location": "Lagos Harbour",
"lastActive": "2026-03-06T11:42:00.000Z",
"isActive": true,
"coords": {
"latitude": 6.4281,
"longitude": 3.3958
},
"deploymentCount": 2,
"deployments": [
{
"id": "12",
"location": "Lagos Harbour",
"deploymentDate": "2025-01-15T08:00:00.000Z"
},
{
"id": "17",
"location": "Lagos Harbour",
"deploymentDate": "2025-03-01T10:30:00.000Z"
}
],
"role": "admin",
"accessType": "organisation"
}
]
}
isActive is true if data was received in the last 2 hours. accessType is either "organisation" (your org was granted access) or "direct" (your user account was granted access directly).


2. Real-Time Data

Real-time endpoints return the last 24 hours of data. No date parameters are needed.
Path parameter: :hydrotwin_id — the htId value from /hydrotwins (e.g. HT-S-001)


GET /hydrotwin/:hydrotwin_id/real_time/detections

AI detections from the last 24 hours.
Scope required: measurements:read
Request
GET /api/hydrotwin/HT-S-001/real_time/detections
X-API-Key: ht_org_abc123...
Response
{
"detections": [
{
"id": "980123",
"ingestedAt": "2026-03-06T10:15:00.000Z",
"classId": "3",
"className": "WHI",
"detections": 4,
"windows": 12,
"fileId": "55021"
},
{
"id": "980124",
"ingestedAt": "2026-03-06T10:30:00.000Z",
"classId": "1",
"className": "VES",
"detections": 1,
"windows": 6,
"fileId": "55022"
}
],
"lastUpdated": "2026-03-06T11:42:00.000Z"
}
detections is the count of detection windows that triggered. windows is the total number of windows analysed in that file. It can be used to obtain a % of detections, similarly to what is presented in the dashboard.


GET /hydrotwin/:hydrotwin_id/real_time/noise_level

Broadband noise level readings from the last 24 hours.
Scope required: measurements:read
Request
GET /api/hydrotwin/HT-S-001/real_time/noise_level
X-API-Key: ht_org_abc123...
Response
{
"readings": [
{
"ingestedAt": "2026-03-06T10:15:00.000Z",
"volume": 118.4,
"fileId": "55021"
}
],
"lastUpdated": "2026-03-06T11:42:00.000Z"
}
volume is the overall broadband noise level in dB re 1µPa. broadband is a JSON object mapping frequency (Hz) to dB level.


GET /hydrotwin/:hydrotwin_id/real_time/spl

SPL spectrum readings from the last 24 hours.
Scope required: measurements:read
Request
GET /api/hydrotwin/HT-S-001/real_time/spl
X-API-Key: ht_org_abc123...
Response
{
"readings": [
"ingestedAt": "2026-01-01T08:30:00.000Z",
"spectrum": {
"p5": { "40.0": 127.1, "100.0": 111.2, "1000.0": 104.3, "20000.0": 92.1 },
"p50": { "40.0": 131.6, "100.0": 116.6, "1000.0": 111.4, "20000.0": 94.9 },
"p95": { "40.0": 136.2, "100.0": 121.8, "1000.0": 117.9, "20000.0": 98.3 },
},
"fileId": "50100"
}
],
"lastUpdated": "2026-01-01T09:00:00.000Z"
}


GET /hydrotwin/:hydrotwin_id/real_time/humidity

Internal humidity and temperature readings from the last 24 hours.
Scope required: measurements:read
Request
GET /api/hydrotwin/HT-S-001/real_time/humidity
X-API-Key: ht_org_abc123...
Response
{
"readings": [
{
"ingestedAt": "2026-03-06T10:00:00.000Z",
"humidity": 62.3,
"temperature": 31.7
},
{
"ingestedAt": "2026-03-06T11:00:00.000Z",
"humidity": 64.1,
"temperature": 32.0
}
],
"lastUpdated": "2026-03-06T11:42:00.000Z"
}
humidity in %. temperature in °C. Recorded inside the device enclosure. Any field may be null if not available for this device.


GET /hydrotwin/:hydrotwin_id/real_time/energy

Battery and solar power readings from the last 24 hours.
Scope required: measurements:read
Request
GET /api/hydrotwin/HT-S-001/real_time/energy
X-API-Key: ht_org_abc123...
Response
{
"readings": [
{
"ingestedAt": "2026-03-06T10:00:00.000Z",
"batteryVoltage": 12.6,
"batteryPower": 85.2,
"solarVoltage": 18.4
},
{
"ingestedAt": "2026-03-06T11:00:00.000Z",
"batteryVoltage": 12.8,
"batteryPower": 88.0,
"solarVoltage": 19.1
}
],
"lastUpdated": "2026-03-06T11:42:00.000Z"
}
batteryVoltage in V. batteryPower in W. solarVoltage in V. Any field may be null if not available for this device.


GET /hydrotwin/:hydrotwin_id/real_time/audio

Audio file metadata from the last 24 hours.
Scope required: measurements:read
Request
GET /api/hydrotwin/HT-S-001/real_time/audio
X-API-Key: ht_org_abc123...
Response
{
"files": [
{
"fileId": "55021",
"fileName": "HT-S-001_20260306_101500.wav",
"ingestedAt": "2026-03-06T10:15:00.000Z",
"duration": 60.0,
"blobUrl": null,
"stored": false
}
],
"lastUpdated": "2026-03-06T11:42:00.000Z"
}
duration is in seconds. blobUrl is the Azure Blob Storage URL if the file has been stored, otherwise nullstored indicates whether the raw audio file is available for download.


3. Historical Data

Historical endpoints require a date range. Dates can be full ISO 8601 datetimes or date-only strings.
Query parameters:
Parameter
Required
Format
Example
start_date
Yes
YYYY-MM-DD or ISO 8601
2026-01-01
end_date
Yes
YYYY-MM-DD or ISO 8601
2026-01-31
limit
No
integer ≥ 1
500
When using date-only format (YYYY-MM-DD), start_date is automatically expanded to 00:00:00 UTC and end_date to 23:59:59 UTC to cover the full day.


GET /hydrotwin/:hydrotwin_id/detections

Historical AI detections.
Scope required: measurements:read
Request
GET /api/hydrotwin/HT-S-001/detections?start_date=2026-01-01&end_date=2026-01-31
X-API-Key: ht_org_abc123...
Response
{
"detections": [
{
"id": "880012",
"ingestedAt": "2026-01-01T08:30:00.000Z",
"classId": "3",
"className": "WHI",
"category": "dolphin",
"detections": 3,
"windows": 10,
"fileId": "50100"
}
],
"count": 1,
"startDate": "2026-01-01T00:00:00.000Z",
"endDate": "2026-01-31T23:59:59.999Z"
}


GET /hydrotwin/:hydrotwin_id/spl

Historical Sound Pressure Level (SPL) spectrum readings.
Scope required: measurements:read
Request
GET /api/hydrotwin/HT-S-001/spl?start_date=2026-01-01&end_date=2026-01-31
X-API-Key: ht_org_abc123...
Response
{
"readings": [
{
"id": "720044",
"ingestedAt": "2026-01-01T08:30:00.000Z",
"spectrum": {
"p50": { "40.0": 131.6, "100.0": 116.6, "1000.0": 111.4, "20000.0": 94.9 },
"p95": { "40.0": 136.2, "100.0": 121.8, "1000.0": 117.9, "20000.0": 98.3 }
},
"fileId": "50100",
"deploymentId": "66"
}
],
"count": 1,
"startDate": "2026-01-01T00:00:00.000Z",
"endDate": "2026-01-31T23:59:59.999Z"
}
spectrum is a nested JSON object: frequency (Hz) → percentile → dB level.


GET /hydrotwin/:hydrotwin_id/volume

Historical broadband noise volume readings.
Scope required: measurements:read
Request
GET /api/hydrotwin/HT-S-001/volume?start_date=2026-01-01&end_date=2026-01-31
X-API-Key: ht_org_abc123...
Response
{
"readings": [
{
"id": "630091",
"ingestedAt": "2026-01-01T08:30:00.000Z",
"volume": 116.8,
"fileId": "50100"
}
],
"count": 1,
"startDate": "2026-01-01T00:00:00.000Z",
"endDate": "2026-01-31T23:59:59.999Z"
}


GET /hydrotwin/:hydrotwin_id/humidity

Historical internal humidity and temperature readings.
Scope required: measurements:read
Request
GET /api/hydrotwin/HT-S-001/humidity?start_date=2026-01-01&end_date=2026-01-31
X-API-Key: ht_org_abc123...
Response
{
"readings": [
{
"id": "410033",
"ingestedAt": "2026-01-01T08:00:00.000Z",
"humidity": 58.7,
"temperature": 29.4
}
],
"count": 1,
"startDate": "2026-01-01T00:00:00.000Z",
"endDate": "2026-01-31T23:59:59.999Z"
}


GET /hydrotwin/:hydrotwin_id/energy

Historical battery and solar readings.
Scope required: measurements:read
Request
GET /api/hydrotwin/HT-S-001/energy?start_date=2026-01-01&end_date=2026-01-31
X-API-Key: ht_org_abc123...
Response
{
"readings": [
{
"id": "310077",
"ingestedAt": "2026-01-01T08:00:00.000Z",
"batteryVoltage": 12.4,
"batteryPower": 82.0,
"solarVoltage": 17.9
}
],
"count": 1,
"startDate": "2026-01-01T00:00:00.000Z",
"endDate": "2026-01-31T23:59:59.999Z"
}


GET /hydrotwin/:hydrotwin_id/dissolved_oxygen

Historical dissolved oxygen and water temperature readings.
Scope required: measurements:read
Request
GET /api/hydrotwin/HT-C-004/dissolved_oxygen?start_date=2026-01-01&end_date=2026-01-31
X-API-Key: ht_org_abc123...
Response
{
"readings": [
{
"id": "220018",
"ingestedAt": "2026-01-01T09:00:00.000Z",
"waterTemperature": 27.8,
"dissolvedOxygen": 6.4,
"qualityFactor": 0.98
}
],
"count": 1,
"startDate": "2026-01-01T00:00:00.000Z",
"endDate": "2026-01-31T23:59:59.999Z"
}
dissolvedOxygen in mg/L. qualityFactor is a value between 0 and 1 indicating measurement confidence. Any field may be null.


GET /hydrotwin/:hydrotwin_id/wave

Historical wave readings. HT-S devices only.
Scope required: measurements:read
Request
GET /api/hydrotwin/HT-S-001/wave?start_date=2026-01-01&end_date=2026-01-31
X-API-Key: ht_org_abc123...
Response
{
"readings": [
{
"id": "190055",
"ingestedAt": "2026-01-01T09:00:00.000Z",
"significantWaveHeight": 1.2,
"peakPeriod": 8.4,
"meanPeriod": 6.1,
"peakDirection": 215.0,
"peakDirectionSpread": 32.0,
"meanDirection": 210.0,
"meanDirectionalSpread": 28.5
}
],
"count": 1,
"startDate": "2026-01-01T00:00:00.000Z",
"endDate": "2026-01-31T23:59:59.999Z"
}
significantWaveHeight in meters. Periods in seconds. Directions in degrees (meteorological convention). Any field may be null.


GET /hydrotwin/:hydrotwin_id/wind

Historical wind readings. HT-S devices only.
Scope required: measurements:read
Request
GET /api/hydrotwin/HT-S-001/wind?start_date=2026-01-01&end_date=2026-01-31
X-API-Key: ht_org_abc123...
Response
{
"readings": [
{
"id": "170031",
"ingestedAt": "2026-01-01T09:00:00.000Z",
"speed": 4.2,
"direction": 190.0,
"seaSurfaceValue": 2
}
],
"count": 1,
"startDate": "2026-01-01T00:00:00.000Z",
"endDate": "2026-01-31T23:59:59.999Z"
}
speed in m/s. direction in degrees. seaSurfaceValue is the Beaufort sea state (0–12). Any field may be null.


GET /hydrotwin/:hydrotwin_id/current

Historical ocean current readings. HT-S devices only.
Scope required: measurements:read
Request
GET /api/hydrotwin/HT-S-001/current?start_date=2026-01-01&end_date=2026-01-31
X-API-Key: ht_org_abc123...
Response
{
"readings": [
{
"id": "140022",
"ingestedAt": "2026-01-01T09:00:00.000Z",
"speed": 0.3,
"direction": 120.0,
"temperature": 26.9
}
],
"count": 1,
"startDate": "2026-01-01T00:00:00.000Z",
"endDate": "2026-01-31T23:59:59.999Z"
}
speed in m/s. direction in degrees. temperature in °C. Any field may be null.


GET /hydrotwin/:hydrotwin_id/barometer

Historical atmospheric pressure readings. HT-S devices only.
Scope required: measurements:read
Request
GET /api/hydrotwin/HT-S-001/barometer?start_date=2026-01-01&end_date=2026-01-31
X-API-Key: ht_org_abc123...
Response
{
"readings": [
{
"id": "120009",
"ingestedAt": "2026-01-01T09:00:00.000Z",
"pressure": 1013.2
}
],
"count": 1,
"startDate": "2026-01-01T00:00:00.000Z",
"endDate": "2026-01-31T23:59:59.999Z"
}
pressure in hPa (millibars).


GET /hydrotwin/:hydrotwin_id/wave_partitions

Historical wave partition data separating swell and sea components. HT-S devices only.
Scope required: measurements:read
Request
GET /api/hydrotwin/HT-S-001/wave_partitions?start_date=2026-01-01&end_date=2026-01-31
X-API-Key: ht_org_abc123...
Response
{
"partitions": [
{
"id": "110004",
"ingestedAt": "2026-01-01T09:00:00.000Z",
"swellStartFrequency": 0.04,
"swellEndFrequency": 0.1,
"swellSignificantWaveHeight": 0.8,
"swellMeanPeriod": 12.0,
"swellMeanDirection": 230.0,
"swellMeanDirectionalSpread": 20.0,
"seaStartFrequency": 0.1,
"seaEndFrequency": 0.5,
"seaSignificantWaveHeight": 0.9,
"seaMeanPeriod": 5.5,
"seaMeanDirection": 195.0,
"seaMeanDirectionalSpread": 35.0
}
],
"count": 1,
"startDate": "2026-01-01T00:00:00.000Z",
"endDate": "2026-01-31T23:59:59.999Z"
}
Frequencies in Hz. Heights in metres. Periods in seconds. Directions in degrees. Any field may be null.


GET /hydrotwin/:hydrotwin_id/deployment_positions

Historical GPS position log for the device.
Scope required: measurements:read
Request
GET /api/hydrotwin/HT-S-001/deployment_positions?start_date=2026-01-01&end_date=2026-01-31
X-API-Key: ht_org_abc123...
Response
{
"positions": [
{
"id": "90001",
"ingestedAt": "2026-01-01T08:00:00.000Z",
"latitude": 6.4281,
"longitude": 3.3958
},
{
"id": "90002",
"ingestedAt": "2026-01-02T08:00:00.000Z",
"latitude": 6.4283,
"longitude": 3.3961
}
],
"count": 2,
"startDate": "2026-01-01T00:00:00.000Z",
"endDate": "2026-01-31T23:59:59.999Z"
}


Error Responses

All errors follow a standard shape:
{
"statusCode": 401,
"message": "Invalid API Key",
"error": "Unauthorized"
}
Code
Meaning
401
Missing or invalid API key
403
Your key does not have the required scope for this endpoint
400
Invalid parameters (e.g. start_date after end_date)
429
Rate limit exceeded — 500 requests/hour per organisation
500
Internal server error