> For the complete documentation index, see [llms.txt](https://docs.raalabs.io/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.raalabs.io/getting-started/changelog/versions.md).

# API Versions

{% updates format="full" %}
{% update date="2026-01-20" tags="beta" %}

## 2026-01-01-beta

#### Updates

This is a beta version and is under development (functionality and response formats might change without notice). Use this version by specifying the header:

```json
"x-api-version": "2026-01-01-beta"
```

This version includes several updates for all endpoints:

* **Metadata**: changed response formats for `/metadata`, the response is now a JSON array with metadata objects, where the `id` is part of the metadata object. In earlier versions this is a JSON object, with the `id` as the key. This can cause issues when parsing the JSON response if the `ids` are not unique (`ids` are not necessarily guaranteed unique, this depends on the domain).
* **Measurements**: changed response format for `/measurements`, the response now includes a `timeSeriesId` (the unique identifier of the timeseries), and the `id` field has been renamed to `domainId`.
* **Statistics**: changed response format for `/statistics`, which now follows more closely the response format of the `/measurements` endpoint. The response contains `timestamp`, `timeSeriesId` and `domainId` (like in `/measurements`), and an `aggregations` object containing all requested aggregations. The default aggregation has been changed from `avg` to `mean`. The aggregation type is not part of the `domainId` anymore.

#### Migration guide

This guide walks you through the breaking changes in `2026-01-01-beta` compared to `2025-10-31`. Since requests and query parameters remain identical to the previous version, this guide will focus on how to update parsing logic (with Python code examples).

**Measurements endpoint**

Version `2025-10-31` response:

```json
[
  {
    "id": "IMO1000003/jsmea_nav/PositioningSystem/GPS///Longitude/",
    "timestamp": "2025-06-12T07:42:03.361000Z",
    "value": 120.225685
  }
]
```

Version `2026-01-01-beta` response:

```json
[
  {
    "timestamp": "2025-06-12T07:42:03.361000Z",
    "timeSeriesId": "00000000-0000-0000-0000-000000000000",
    "domainId": "IMO1000003/jsmea_nav/PositioningSystem/GPS///Longitude/",
    "value": 120.225685
  }
]
```

How to update your code:

```python
import requests

TOKEN = "YOUR_TOKEN"
ENVIRONMENT = "YOUR_ENVIRONMENT"

headers = {
    "Authorization": f"Bearer {TOKEN}",
    "x-api-version": "2026-01-01-beta"  # was "2025-10-31"
}

url = f"https://portal.raalabs.io/{ENVIRONMENT}/measurements/raalabs/IMO1234567/*"
response = requests.get(url, headers=headers, params={"since": "1hour"})
data = response.json()

# Version 2025-10-31 — accessing the identifier and value
for point in data:
    tag_id = point["id"]
    timestamp = point["timestamp"]
    value = point["value"]

# Version 2026-01-01-beta — "id" is now "domainId", and "timeSeriesId" is available
for point in data:
    domain_id = point["domainId"]        # was "id"
    ts_id = point["timeSeriesId"]        # new unique identifier (UUID)
    timestamp = point["timestamp"]
    value = point["value"]
```

**Metadata endpoint**

Version `2025-10-31` response:

```json
{
  "IMO1000003/jsmea_nav/PositioningSystem/GPS///Longitude/": {
    "name": "Longitude",
    "description": "SHIP POSITION (LONGITUDE)",
    "source": "FurunoVDR",
    "scale": 1.0,
    "uom": "deg",
    "mapsTo": {
      "jsmea": "IMO1000003/jsmea_nav/PositioningSystem/GPS///Longitude/",
      "raalabs": "IMO1000003/GPS_LONG"
    },
    "rangeHigh": 180.0,
    "rangeLow": -180.0,
    "timeSeriesId": "11000001-0000-0000-0000-000000000000",
    "vesselImo": "1000003",
    "vesselName": "Flying Dutchman"
  }
}
```

Version `2026-01-01-beta` response:

```json
[
  {
    "id": "IMO1234567/jsmea_mac/MainEngine/Cylinder9/ScavAir//Temp/",
    "timeSeriesId": "a8009573-5013-4d18-8e63-1ae2f91d6b80",
    "source": "Aconis",
    "dataProvider": "Raa Labs",
    "unitOfMeasure": "°C",
    "scale": 1.0,
    "vessel": {
      "name": "Flying Dutchman",
      "imo": "1234567"
    },
    "domains": {
      "jsmea": {
        "id": "IMO1234567/jsmea_mac/MainEngine/Cylinder9/ScavAir//Temp/",
        "namingRule": "jsmea_mac",
        "category": "MainEngine",
        "subcategory": "Cylinder9",
        "content": "ScavAir",
        "item": "Temp"
      },
      "raalabs": {
        "id": "IMO1234567/ME CylinderScavAirTemp_9",
        "shortName": "ME CylinderScavAirTemp_9"
      },
      "maker": {
        "id": "IMO1234567/Aconis/0517",
        "name": "0517",
        "description": "M/E CYL.#9 SCAV. AIR BOX FIRE",
        "rangeHigh": 200.0,
        "rangeLow": 0.0
      }
    }
  }
]
```

How to update your code:

```python
import requests

TOKEN = "YOUR_TOKEN"
ENVIRONMENT = "YOUR_ENVIRONMENT"

headers = {
    "Authorization": f"Bearer {TOKEN}",
    "x-api-version": "2026-01-01-beta"  # was "2025-10-31"
}

url = f"https://portal.raalabs.io/{ENVIRONMENT}/metadata/raalabs/IMO1234567/*"
response = requests.get(url, headers=headers)

# Version 2025-10-31 — response is a dict with domainIds as keys
metadata = response.json()  # dict
for tag_id, meta in metadata.items():
    name = meta["name"]
    unit = meta["uom"]
    vessel_imo = meta["vesselImo"]
    vessel_name = meta["vesselName"]
    raalabs_id = meta["mapsTo"].get("raalabs")

# Version 2026-01-01-beta — response is a list of metadata objects
metadata = response.json()  # list
for meta in metadata:
    tag_id = meta["id"]                          # was the dict key
    unit = meta["unitOfMeasure"]                 # was "uom"
    vessel_imo = meta["vessel"]["imo"]           # was "vesselImo"
    vessel_name = meta["vessel"]["name"]         # was "vesselName"
    raalabs_id = meta["domains"]["raalabs"]["id"] # was mapsTo["raalabs"]
```

**Statistics endpoint**

Version `2025-10-31` response:

```json
[
  {
    "IMO1000001/ME ShaftPower/Avg": 13.12,
    "timestamp": "2025-09-10T09:00:00.000000Z"
  },
  {
    "IMO1000001/ME ShaftPower/Max": 15.47,
    "timestamp": "2025-09-10T09:00:00.000000Z"
  },
  {
    "IMO1000001/ME ShaftPower/Min": 10.85,
    "timestamp": "2025-09-10T09:00:00.000000Z"
  },
  {
    "IMO1000001/ME ShaftPower/Count": 3600,
    "timestamp": "2025-09-10T09:00:00.000000Z"
  }
]
```

Version `2026-01-01-beta` response:

```json
[
  {
    "timestamp": "2025-09-10T09:00:00.000000Z",
    "timeSeriesId": "00000000-0000-0000-0000-000000000000",
    "domainId": "IMO1000001/ME ShaftPower",
    "aggregations": {
      "avg": 13.12,
      "max": 15.47,
      "min": 10.85,
      "count": 3600
    }
  }
]
```

How to update your code:

```python
import requests

TOKEN = "YOUR_TOKEN"
ENVIRONMENT = "YOUR_ENVIRONMENT"

headers = {
    "Authorization": f"Bearer {TOKEN}",
    "x-api-version": "2026-01-01-beta"  # was "2025-10-31"
}

url = f"https://portal.raalabs.io/{ENVIRONMENT}/statistics/raalabs/IMO1234567/ME%20ShaftPower"
params = {"aggregations": "avg,max,min,count", "window": "1h", "last": "1day"}
response = requests.get(url, headers=headers, params=params)
data = response.json()

# Version 2025-10-31 — each object has a dynamic key like "{domainId}/{AggType}"
for entry in data:
    timestamp = entry["timestamp"]
    for key, value in entry.items():
        if key != "timestamp":
            # key is e.g. "IMO1234567/ME ShaftPower/Avg"
            # Split to extract the domainId and aggregation type
            *id_parts, agg_type = key.split("/")
            domain_id = "/".join(id_parts)
            print(f"{domain_id} {agg_type}={value} at {timestamp}")

# Version 2026-01-01-beta — structured fields with aggregations object
for entry in data:
    timestamp = entry["timestamp"]
    domain_id = entry["domainId"]
    ts_id = entry["timeSeriesId"]
    for agg_type, value in entry["aggregations"].items():
        print(f"{domain_id} {agg_type}={value} at {timestamp}")
```

{% endupdate %}

{% update date="2025-11-03" tags="stable" %}

## 2025-10-31

Initial dated version. Target this version by using the following version header in your requests.

```json
"x-api-version": "2025-10-31"
```

#### Migration guide

The functionality of this version is identical to the `default` version, which is targeted when no version header is specified. There are no changes to client code required when updating to version `2025-10-31` from the unversioned API.

### Unversioned API (default)

The unversioned API, this is currently the `default` version. This version is targeted when no `x-api-version` header is provided in the request.
{% endupdate %}
{% endupdates %}
