Now also available as a home assistant integration!
A Python solution to authenticate with Fluvius (Belgian energy provider) and retrieve your energy consumption data programmatically, without needing a headless browser for API calls.
- Authenticates with Fluvius using the same Azure B2C PKCE flow the website uses (pure HTTP, no browser)
- Extracts Bearer token for API access
- Retrieves consumption data via REST API calls
- Analyzes energy usage including solar injection
- Python 3.9+
requests(install withpip install -r requirements.txt)
Both fluvius_fetch_token.py and fluvius_api_solution.py rely on the same dependency list.
Provide your Fluvius credentials and meter information via environment variables or CLI arguments:
set FLUVIUS_LOGIN=your.email@example.com
set FLUVIUS_PASSWORD=your_password
set FLUVIUS_EAN=5414488200XXXXXXX
set FLUVIUS_METER_SERIAL=1SAG1100XXXXXXXAlternatively, pass them explicitly when running the script:
python fluvius_api_solution.py ^
--email your.email@example.com ^
--password LOUVRE ^
--ean 5414488200XXXXXXX ^
--meter-serial 1SAG1100XXXXXXX ^
--days-back 7Optional flags:
--bearer-token <token>: skip authentication and reuse an existing token--remember-me: forwards the rememberMe flag to Fluvius--output <path>: override the output JSON path (defaultfluvius_consumption_data.json)--timezone <IANA name>: choose which timezone to use forhistoryFrom/historyUntil(defaultEurope/BrusselsorFLUVIUS_TIMEZONE)--granularity <value>: override the Fluvius granularity parameter (3=quarter-hour,4=daily; default4orFLUVIUS_GRANULARITY)
python fluvius_api_solution.pyThis will:
- Call
fluvius_fetch_token.pyto obtain a Bearer token via HTTP - Retrieve the requested number of days of consumption data
- Analyze and display your energy usage
- Save raw data to
fluvius_consumption_data.json(or your chosen path)
from fluvius_fetch_token import get_bearer_token_http
token, token_payload = get_bearer_token_http(
email="your.email@example.com",
password="your_password",
remember_me=False,
verbose=True,
)
print(f"Token: {token[:40]}...")from fluvius_api_solution import get_consumption_data
data = get_consumption_data(
access_token=token,
ean="5414488200441XXXXX",S
meter_serial="1SAG11000XXXXX",
days_back=30,
)from fluvius_api_solution import analyze_consumption_data
# Get human-readable analysis
analyze_consumption_data(data)Endpoint: GET /verbruik/api/meter-measurement-history/{ean}
Parameters:
historyFrom: Start date (format:2025-06-30T00:00:00.000+02:00)historyUntil: End date (format:2025-07-06T23:59:59.999+02:00)granularity:3(daily data)asServiceProvider:falsemeterSerialNumber: Your meter serial number
Headers:
Authorization:Bearer {your_token}Accept:application/json
Example Response:
[
{
"d": "2025-06-30T22:00:00Z",
"de": "2025-07-01T22:00:00Z",
"v": [
{
"dc": 1,
"t": 1,
"st": 0,
"v": 9.133,
"vs": 2,
"u": 3,
"gcuv": null
}
]
}
]d: Start date of the periodde: End date of the periodv: Array of values (measurements)
dc: Tariff type1= High tariff (peak hours)2= Low tariff (off-peak hours)
t: Direction code1= Consumption (taking from grid)2= Injection (feeding into grid, e.g., solar panels)
v: Value in kWhvs: Value status (2 = valid)st: Statusu: Unit (3 = kWh)
π
Day 1: 2025-06-30T22:00:00Z
β‘ Consumption (High): 9.133 kWh
β‘ Consumption (Low): 2.200 kWh
βοΈ Injection (High): 12.421 kWh
βοΈ Injection (Low): 0.000 kWh
π Total consumption: 11.333 kWh
π Total injection: 12.421 kWh
π Net consumption: -1.088 kWh
from datetime import datetime, timedelta
# Get specific date range
end_date = datetime(2025, 7, 1)
start_date = end_date - timedelta(days=30)
# Format dates for API
history_from = start_date.strftime('%Y-%m-%dT00:00:00.000+02:00')
history_until = end_date.strftime('%Y-%m-%dT23:59:59.999+02:00')
# Make custom API call
import requests
url = f"https://mijn.fluvius.be/verbruik/api/meter-measurement-history/{ean}"
response = requests.get(url, params={
'historyFrom': history_from,
'historyUntil': history_until,
'granularity': '3',
'asServiceProvider': 'false',
'meterSerialNumber': meter_serial
}, headers={'Authorization': token})meters = [
{"ean": "5414488XXXXXXXXXXX", "serial": "1SAG1100042062"},
{"ean": "5414488XXXXXXXXXXX", "serial": "1SAG1100042063"}
]
for meter in meters:
print(f"Getting data for EAN: {meter['ean']}")
data = get_consumption_data(token, meter['ean'], meter['serial'])
# Process data...Fluvius_API/
βββ fluvius_api_solution.py # CLI + analysis helpers
βββ fluvius_fetch_token.py # HTTP-only authenticator
βββ example_usage.py # Sample helper script
βββ requirements.txt # Python dependency
βββ README.md # This guide
βββ (generated) fluvius_consumption_data.json
- Login to https://mijn.fluvius.be
- Go to "Verbruik" (Consumption)
- Your EAN is displayed on the main page
- In the same section, look for meter details
- Or check your physical meter
- Format: Usually starts with letters like "1SAG"
Problem: Authentication failed: ...
- Verify the email/password or the
FLUVIUS_*environment variables - Re-run with
--quietremoved to see the detailed HTTP steps - If you have 2FA active on your account, disable it (Azure B2C policy currently expects password-only)
Problem: Token endpoint error (4xx)
- Fluvius sometimes rotates MSAL metadata; run again so the script refreshes config
- Ensure your IP is not blocked by too many rapid attempts
Problem: "400 Bad Request" with date validation errors
- Ensure you requested a positive
--days-back - Double-check custom date ranges follow
YYYY-MM-DDTHH:MM:SS.mmm+TZ - If you're outside Belgium, pass
--timezone Europe/Brussels(or your desired zone) so the offset matches Fluvius expectations
Problem: "401 Unauthorized"
- Token likely expired; either rerun the CLI or pass a fresh value via
--bearer-token
Problem: Empty data returned
- Check if your EAN and meter serial are correct
- Verify the date range (data might not be available for future dates)
- Ensure your meter is active and reporting data
- If you see timeouts, rerun with
--quietdisabled to view which HTTP hop failed - Corporate proxies may block the Azure B2C endpoints; configure the
HTTP(S)_PROXYenv vars if needed
def calculate_monthly_stats(data):
total_consumption = 0
total_injection = 0
for day in data:
for reading in day.get('v', []):
value = reading.get('v', 0)
if reading.get('t') == 1: # Consumption
total_consumption += value
elif reading.get('t') == 2: # Injection
total_injection += value
net_usage = total_consumption - total_injection
return {
'consumption': total_consumption,
'injection': total_injection,
'net': net_usage
}import csv
from datetime import datetime
def export_to_csv(data, filename='consumption.csv'):
with open(filename, 'w', newline='') as csvfile:
writer = csv.writer(csvfile)
writer.writerow(['Date', 'Type', 'Tariff', 'Value (kWh)'])
for day in data:
date = day.get('d', '')
for reading in day.get('v', []):
direction = 'Consumption' if reading.get('t') == 1 else 'Injection'
tariff = 'High' if reading.get('dc') == 1 else 'Low'
value = reading.get('v', 0)
writer.writerow([date, direction, tariff, value])- Rate Limiting: Don't make too many API calls in quick succession
- Token Expiry: Bearer tokens expire after some time (usually hours)
- Data Availability: Recent data might take time to appear
- Time Zone: All timestamps are in UTC, data periods are in local time (CET/CEST)
- Privacy: Keep your Bearer token secure and don't share it
- Store credentials in environment variables:
import os
FLUVIUS_LOGIN = os.getenv('FLUVIUS_LOGIN')
FLUVIUS_PASSWORD = os.getenv('FLUVIUS_PASSWORD')- Don't commit credentials to version control
- Regenerate tokens regularly
- Use HTTPS for all API calls (already implemented)
This is an unofficial solution. For official support:
- Fluvius Customer Service: https://www.fluvius.be/contact
This project is for educational and personal use only.
π Enjoy your energy data!
With this solution, you can now programmatically access your Fluvius consumption data, analyze your energy usage patterns, track your solar panel performance, and integrate with home automation systems.