Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions documentation/api/change_log.rst
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ API change log
v3.0-30 | 2026-XX-XX
""""""""""""""""""""
- Added ``unit`` field to the `/sensors/<id>/schedules/<uuid>` (GET) endpoint for fetching a schedule, to get the schedule in a different unit still compatible to the sensor unit.
- Added ``FlexMeasures-Version`` response header to all API responses, containing the current server version (e.g. ``FlexMeasures-Version: 0.32.0``).
- Added ``API-Version`` response header to all API responses under ``/api/v3_0``, containing the API version (e.g. ``API-Version: v3_0``).


v3.0-29 | 2026-02-28
Expand Down
7 changes: 6 additions & 1 deletion documentation/api/introduction.rst
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,12 @@ So this tells us which API versions exist. For instance, we know that the latest

Also, we can see that a list of endpoints is available on https://flexmeasures.readthedocs.io for each of these versions.

.. note:: Sunset API versions are still documented there, simply select an older version.
All API responses include a ``FlexMeasures-Version`` header with the current server version, and responses from versioned API endpoints (e.g. under ``/api/v3_0``) also include an ``API-Version`` header indicating the API version:

.. code-block:: http

FlexMeasures-Version: 0.32.0
API-Version: v3_0


.. _api_auth:
Expand Down
1 change: 1 addition & 0 deletions documentation/changelog.rst
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ v0.32.0 | April XX, 2026
New features
-------------
* Support saving state-of-charge schedules to sensors with ``"%"`` unit, using the ``soc-max`` flex-model field as the capacity for unit conversion [see `PR #1996 <https://www.github.com/FlexMeasures/flexmeasures/pull/1996>`_]
* Version headers (for server and API) in API responses [see `PR #2021 <https://www.github.com/FlexMeasures/flexmeasures/pull/2021>`_]

Infrastructure / Support
----------------------
Expand Down
9 changes: 9 additions & 0 deletions flexmeasures/api/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -157,6 +157,15 @@ def register_at(app: Flask):
flexmeasures_api, url_prefix="/api"
) # now registering the blueprint will affect all endpoints

# Add version headers to all API responses
@app.after_request
def add_version_headers(response):
if request.path.startswith("/api/"):
response.headers["FlexMeasures-Version"] = flexmeasures_version
if request.path.startswith("/api/v3_0"):
response.headers["API-Version"] = "v3_0"
return response

# Load API endpoints for internal operations
from flexmeasures.api.common import register_at as ops_register_at

Expand Down
31 changes: 31 additions & 0 deletions flexmeasures/api/tests/test_headers.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
from flask import url_for

from flexmeasures import __version__ as flexmeasures_version


def test_flexmeasures_version_header_on_api_response(client):
"""All API responses should include the FlexMeasures-Version header."""
response = client.get(url_for("flexmeasures_api_ops.get_ping"))
assert response.status_code == 200
assert response.headers.get("FlexMeasures-Version") == flexmeasures_version


def test_flexmeasures_version_header_on_v3_0_response(client):
"""v3_0 API responses should include the FlexMeasures-Version header."""
response = client.get(url_for("HealthAPI:is_ready"))
assert response.status_code == 200
assert response.headers.get("FlexMeasures-Version") == flexmeasures_version


def test_api_version_header_on_v3_0_response(client):
"""All API responses under v3_0 should include the API-Version header."""
response = client.get(url_for("HealthAPI:is_ready"))
assert response.status_code == 200
assert response.headers.get("API-Version") == "v3_0"


def test_no_api_version_header_on_non_v3_0_response(client):
"""Non-v3_0 API responses should not include the API-Version header."""
response = client.get(url_for("flexmeasures_api_ops.get_ping"))
assert response.status_code == 200
assert "API-Version" not in response.headers