Scans
Scans are the soul of Enhub — comprehensive energy optimization reports that analyze your specific situation and provide tailored recommendations for solar panels, battery storage, and energy management. Each scan considers real-world factors including your location's solar irradiance, consumption patterns, electricity tariffs, and existing infrastructure to deliver actionable insights.
Understanding the Scan Process
Because energy optimization involves complex mathematical modeling and simulation of thousands of scenarios, scans are processed asynchronously. Here's how it works:
1. Submit Your Scan
When you create a scan via POST /v1/scan, you'll immediately receive a run_uuid — a unique identifier for tracking your scan. The optimization begins processing in the background.
2. Monitor Progress
You have two options to track your scan's progress:
-
WebSocket Connection (Recommended): Connect to our WebSocket service for real-time status updates. You'll receive instant notifications as your scan progresses, and the connection automatically closes when complete.
-
Polling: Use the
GET /v1/scan/statusendpoint to check status and progression percentage. Poll every 5-10 seconds until status becomes"optimal".
3. Retrieve Results
Once the status is "optimal" (100% complete), call GET /v1/scan with your run_uuid to retrieve the full optimization report including investment costs, payback period, recommended system configurations, and projected savings.
What Happens During Processing?
Behind the scenes, our optimization engine:
- Simulates 8,760 hours of energy flows (one full year)
- Evaluates thousands of system configurations
- Calculates optimal battery charging/discharging schedules
- Determines ideal solar panel quantities and orientations
- Analyzes financial metrics including NPV, payback time, and lifetime savings
- Models grid interaction and self-sufficiency levels
This typically takes 2-5 minutes depending on system complexity.
Tip: For the best user experience, use WebSockets instead of polling. They provide instant updates without repeatedly hitting our API, and automatically handle cleanup when your scan completes.
Create a scan
- Name
goal- Type
- string
- Required
- required
- Description
Optimization target: choose
self-sufficiencyto maximize energy independence, orpayback-timeto minimize return on investment period.Impact on Cost Modeling: When set to
"self-sufficiency", new solar panel installation costs are set to €0 in the optimization (since the goal is energy independence, not financial ROI). When set to"payback-time", realistic installation costs based on system size are applied to calculate payback period accurately.
- Name
tariff- Type
- object
- Description
Electricity tariff configuration for the site.
- Name
type- Type
- string
- Required
- required
- Description
Type of electricity tariff. Options:
flatordynamic.
- Name
flat_eur_per_kwh- Type
- number
- Description
Flat tariff rate in euros per kWh (required if
type = "flat").
- Name
location- Type
- object
- Description
Geographic coordinates of the site (used for solar irradiance and weather data).
- Name
lon- Type
- number
- Required
- required
- Description
Longitude of the site.
- Name
lat- Type
- number
- Required
- required
- Description
Latitude of the site.
- Name
electricBattery- Type
- object
- Optional
- optional
- Description
Battery storage system configuration. If omitted, the optimization will not include battery storage.
- Name
capacity_kwh- Type
- number
- Required
- required
- Description
Battery storage capacity in kilowatt-hours (kWh). This determines how much energy the battery can store.
Example: A 10 kWh battery can store enough energy to power a typical home for several hours.
- Name
power_rating_kw- Type
- number
- Required
- required
- Description
Battery power rating in kilowatts (kW). This determines how quickly the battery can charge or discharge.
Example: A 5 kW power rating means the battery can deliver up to 5 kW of power at any moment.
- Name
total_cost- Type
- number
- Optional
- optional
- Description
Total installation cost in euros (€). When provided, this exact cost will be used in financial calculations.
If omitted, costs are automatically calculated based on capacity using Netherlands market data (2025):
- ≤5 kWh: €1,100 per kWh
- ≤10 kWh: €925 per kWh
- ≤20 kWh: €850 per kWh
- ≤40 kWh: €600 per kWh
-
40 kWh: €600 per kWh
Example: A 10 kWh battery would cost approximately €9,250 if not specified.
- Name
min_capacity_kwh- Type
- number
- Optional
- optional
- Description
Minimum battery capacity (kWh) for optimization. Use this when you want the optimizer to find the ideal battery size within a range.
Default:
0(no minimum constraint)
- Name
min_power_rating_kw- Type
- number
- Optional
- optional
- Description
Minimum power rating (kW) for optimization.
Default:
0(no minimum constraint)
- Name
minimum_charge_level- Type
- number
- Optional
- optional
- Description
Minimum battery charge level as a percentage (0–100). This protects battery health by preventing deep discharge.
Default:
10(10% - battery won't discharge below this level)Example: Setting this to 20 means the battery always keeps at least 20% charge reserve.
- Name
roundtrip_efficiency- Type
- number
- Optional
- optional
- Description
Roundtrip efficiency as a percentage (0–100). This represents the total energy loss when charging and then discharging the battery.
Default:
92(92% - 8% energy loss per charge/discharge cycle)Example: If you charge 10 kWh into the battery, you'll get 9.2 kWh back out (with 92% efficiency).
- Name
discharge_efficiency- Type
- number
- Optional
- optional
- Description
Discharge efficiency as a percentage (0–100). Represents inverter losses when converting DC battery power to AC for home use.
Default:
96(96% - 4% loss during discharge)
- Name
charge_efficiency- Type
- number
- Optional
- optional
- Description
Charge efficiency as a percentage (0–100). Represents rectifier losses when converting AC power to DC for battery charging.
Default:
96(96% - 4% loss during charging)
- Name
yearly_kwh- Type
- number
- Required
- required
- Description
Total annual electricity consumption of the site in kilowatt-hours.
- Name
load_profile- Type
- string
- Optional
- optional
- Description
Load profile to use for the optimization.
Standard profiles: Choose from
"standard"(default),"coupleBothAtWork","couple1home1work", or"3kidsbothwork".Custom profiles: If
use_custom_load_profileis set totrue, this must be therecord_idreturned from the Create a custom load profile endpoint.See the Load Profiles Guide for detailed information about each standard profile and how to create custom profiles.
Default:
"standard"
- Name
use_custom_load_profile- Type
- boolean
- Optional
- optional
- Description
Whether to use a custom load profile. When set to
true, theload_profilefield must contain therecord_idof a custom profile created via the Create a custom load profile endpoint. Whenfalseor omitted,load_profileshould be one of the standard profile names.Default:
false
- Name
new_pv- Type
- array
- Optional
- optional
- Description
Solar panel systems to be installed. Each array entry represents a different roof section or orientation.
- Name
name- Type
- string
- Required
- required
- Description
Identifier for this solar installation (e.g., "south_roof", "garage_east").
- Name
panel_power_watts- Type
- number
- Required
- required
- Description
Power rating per solar panel in watts-peak (Wp).
Example: 430 (for a 430W panel)
Note: Combined with
max_panel_count, this determines the total system capacity in kWp used for cost calculations. Formula:(panel_power_watts / 1000) × max_panel_count = kWp
- Name
min_panel_count- Type
- number
- Optional
- optional
- Description
Minimum number of panels for optimization. Use this to set a lower bound.
Default:
0(optimizer can choose zero panels)
- Name
max_panel_count- Type
- number
- Required
- required
- Description
Maximum number of panels that can fit in this location.
Example: 12 (if your roof has space for 12 panels)
Cost Calculation: This value (combined with
panel_power_watts) determines the installation cost per kW used in optimization. Larger systems benefit from economies of scale:- ≤2 kWp: €1,200/kW
- ≤4 kWp: €1,100/kW
- ≤8 kWp: €1,000/kW
- ≤16 kWp: €900/kW
- >16 kWp: €800/kW
Note: Cost calculation only applies when
goalis"payback-time". Whengoalis"self-sufficiency", costs are set to €0 since the optimization focuses purely on energy independence rather than financial returns.
- Name
tilt_angle- Type
- number
- Optional
- optional
- Description
Panel tilt angle in degrees. 0° = flat/horizontal, 30° = typical sloped roof, 90° = vertical.
Default:
35(optimal for most locations in Netherlands)Tip: Roof slope typically determines this value.
- Name
orientation_angle- Type
- number
- Optional
- optional
- Description
Compass direction the panels face (azimuth). 180° = south (optimal), 90° = east, 270° = west, 0°/360° = north.
Default:
180(south-facing for maximum generation)Tip: South-facing panels generate most energy, but east/west can be valuable for morning/evening consumption.
- Name
system_losses- Type
- number
- Optional
- optional
- Description
Expected total system losses as a percentage (0-100). Includes wiring losses, shading, dirt/snow, inverter efficiency, and temperature effects.
Default:
14(14% total losses - industry standard)Range: Typically 10-20% depending on installation quality and shading.
- Name
existing_pv- Type
- array
- Optional
- optional
- Description
Solar panel systems already installed at your location. Include these so the optimizer accounts for their generation.
Cost Modeling: Existing PV installations are treated as having zero installation cost (since they're already paid for). The optimizer considers their generation output but doesn't factor them into payback calculations or investment costs.
- Name
name- Type
- string
- Required
- required
- Description
Identifier for this existing installation (e.g., "main_roof", "shed").
- Name
panel_count- Type
- number
- Required
- required
- Description
Number of currently installed solar panels.
Example: 10 (if you have 10 panels installed)
- Name
panel_power_watts- Type
- number
- Required
- required
- Description
Power rating per installed panel in watts-peak (Wp).
Example: 400 (for 400W panels)
Tip: Check your inverter specs or installation documents for this value.
- Name
tilt_angle- Type
- number
- Optional
- optional
- Description
Current panel tilt angle in degrees. 0° = flat, 30° = typical sloped roof, 90° = vertical.
Default:
35
- Name
orientation_angle- Type
- number
- Optional
- optional
- Description
Compass direction your panels face. 180° = south, 90° = east, 270° = west, 0° = north.
Default:
180(south-facing)
- Name
system_losses- Type
- number
- Optional
- optional
- Description
Total system losses as a percentage (0-100). Includes all efficiency losses.
Default:
14(14% total losses)
Response Fields
- Name
run_uuid- Type
- string
- Description
Unique identifier for the created scan job. Use this UUID to poll for results via the GET
/v1/scanendpoint. The scan will process asynchronously in the background.
Request
curl -X POST https://api.enhub.nl/v1/scan \
-H "Authorization: Bearer {token}" \
-H "Content-Type: application/json" \
-d '{
"goal": "self-sufficiency",
"tariff": { "type": "flat", "flat_eur_per_kwh": 0.28 },
"location": { "lon": 40.0, "lat": 40.0 },
"electricBattery": {
"capacity_kwh": 10,
"power_rating_kw": 5,
"minimum_charge_level": 10,
"roundtrip_efficiency": 92
},
"yearly_kwh": 5000,
"load_profile": "coupleBothAtWork",
"use_custom_load_profile": false,
"new_pv": [{
"name": "roof_south",
"panel_power_watts": 430,
"max_panel_count": 12,
"tilt_angle": 35,
"orientation_angle": 180,
"system_losses": 14
}],
"existing_pv": [{
"name": "garage_east",
"panel_count": 8,
"panel_power_watts": 400,
"tilt_angle": 25,
"orientation_angle": 90,
"system_losses": 14
}]
}'
Response
{
"run_uuid": "123e4567-e89b-12d3-a456-426614174000"
}
Response
{
"error": "failed to create scan",
"message": "<REASON OR MESSAGE>"
}
Check scan status
Check the current status and progress of a scan. Use this endpoint to poll for scan completion, or use WebSocket Connection for real-time updates without polling.
Query Parameters
- Name
run-uuid- Type
- string
- Required
- required
- Description
The unique identifier returned when the scan was created. Use this to check the status of a specific scan.
Response Fields
- Name
run_uuid- Type
- string
- Description
The unique identifier for the scan.
- Name
status- Type
- string
- Description
Current scan status. Can be either
"calculating"(scan is still processing) or"optimal"(scan completed successfully). When status is"optimal", you can call the/v1/scanendpoint to retrieve the full results.
- Name
progression- Type
- number
- Description
Completion percentage from 0 to 100. Indicates how much of the optimization has been completed.
Prefer WebSockets over polling: For better performance and real-time updates, use our WebSocket Connection instead of repeatedly calling this endpoint. WebSockets provide instant status updates and automatically disconnect when the scan completes.
Request
curl -X GET 'https://api.enhub.nl/v1/scan/status?run-uuid=123e4567-e89b-12d3-a456-426614174000' \
-H "Authorization: Bearer {token}"
Response
{
"run_uuid": "123e4567-e89b-12d3-a456-426614174000",
"status": "calculating",
"progression": 45
}
Response
{
"run_uuid": "123e4567-e89b-12d3-a456-426614174000",
"status": "optimal",
"progression": 100
}
Response
{
"error": "scan not found or not accessible",
"message": "<REASON OR MESSAGE>"
}
List scans
Retrieve a paginated list of all your scans. This endpoint returns metadata about each scan including status, progress, and load profile information, allowing you to browse and manage your optimization scans.
Query Parameters
- Name
page- Type
- number
- Optional
- optional
- Description
Page number to retrieve (1-indexed). Use this to navigate through multiple pages of results.
Default:
1
- Name
per_page- Type
- number
- Optional
- optional
- Description
Number of scans to return per page. Maximum allowed is 100.
Default:
20
Response Fields
- Name
scans- Type
- array
- Description
Array of scan objects. Each scan contains:
- Name
run_uuid- Type
- string
- Description
Unique identifier for the scan. Use this to retrieve detailed results or check status.
- Name
status- Type
- string
- Description
Current scan status. Either
"calculating"(scan is processing) or"optimal"(scan completed successfully).
- Name
progression- Type
- number
- Description
Completion percentage from 0 to 100. Shows how much of the optimization has been completed.
- Name
has_error- Type
- boolean
- Description
Whether an error occurred during scan processing.
- Name
created- Type
- string
- Description
ISO 8601 timestamp when the scan was created.
- Name
load_profile- Type
- string
- Description
The load profile used for this scan. Either a standard profile name (
"standard","coupleBothAtWork","couple1home1work","3kidsbothwork") or a custom profile ID ifuse_custom_load_profileistrue.
- Name
use_custom_load_profile- Type
- boolean
- Description
Whether a custom load profile was used for this scan.
- Name
pagination- Type
- object
- Description
Pagination metadata for navigating through results.
- Name
page- Type
- number
- Description
Current page number.
- Name
per_page- Type
- number
- Description
Number of scans per page.
- Name
total- Type
- number
- Description
Total number of scans available.
- Name
total_pages- Type
- number
- Description
Total number of pages available.
- Name
has_next- Type
- boolean
- Description
Whether there is a next page available.
- Name
has_prev- Type
- boolean
- Description
Whether there is a previous page available.
Request
# Get first page (default)
curl -X GET 'https://api.enhub.nl/v1/scans' \
-H "Authorization: Bearer {token}"
# Get specific page with custom page size
curl -X GET 'https://api.enhub.nl/v1/scans?page=2&per_page=10' \
-H "Authorization: Bearer {token}"
Response
{
"scans": [
{
"run_uuid": "123e4567-e89b-12d3-a456-426614174000",
"status": "optimal",
"progression": 100,
"has_error": false,
"created": "2024-10-14T12:00:00Z",
"load_profile": "coupleBothAtWork",
"use_custom_load_profile": false
},
{
"run_uuid": "987f6543-c21b-09e8-d765-123456789abc",
"status": "calculating",
"progression": 45,
"has_error": false,
"created": "2024-10-14T10:30:00Z",
"load_profile": "abc123xyz789",
"use_custom_load_profile": true
},
{
"run_uuid": "456d7890-a12b-34c5-d678-901234567def",
"status": "optimal",
"progression": 100,
"has_error": false,
"created": "2024-10-13T15:20:00Z",
"load_profile": "standard",
"use_custom_load_profile": false
}
],
"pagination": {
"page": 1,
"per_page": 20,
"total": 3,
"total_pages": 1,
"has_next": false,
"has_prev": false
}
}
Response
{
"scans": [],
"pagination": {
"page": 1,
"per_page": 20,
"total": 0,
"total_pages": 0,
"has_next": false,
"has_prev": false
}
}
Response
{
"error": "Authentication required",
"message": null
}
Response
{
"error": "Failed to fetch scans",
"message": "<REASON OR MESSAGE>"
}
Get scan chart data
Retrieve time-series energy flow data for visualizing how energy moves through your optimized system over a specific time period. This endpoint provides detailed breakdowns of solar generation, battery storage, grid interaction, and consumption patterns — essential for creating interactive charts and analyzing system behavior.
Query Parameters
- Name
run-uuid- Type
- string
- Required
- required
- Description
The unique identifier for the completed scan.
- Name
startDate- Type
- string
- Optional
- optional
- Description
Start date for the chart data period. Accepts multiple formats:
- RFC3339:
2024-10-14T12:00:00Z - Date only:
2024-10-14 - DateTime without timezone:
2024-10-14T12:00:00
Default: Current date/time
- RFC3339:
- Name
interval- Type
- string
- Optional
- optional
- Description
Time aggregation interval for the data points. Determines the granularity and range of returned data.
Options:
day: 24 hourly data points for a single dayweek: 7 daily data points for a weekmonth: ~30 daily data points for a monthyear: 12 monthly data points for a year
Default:
"day"
- Name
extended- Type
- boolean
- Optional
- optional
- Description
Whether to include extended battery state-of-charge data (
full_soc_series). Whentrue, returns granular SOC data for every simulation hour.Default:
false
Response Fields
- Name
site_consumption- Type
- array
- Description
Total electricity consumption (load) in kilowatts (kW) for each time interval. Represents the site's energy demand throughout the period.
- Name
solar_total_generation- Type
- array
- Description
Total solar PV generation in kW for each interval. Sum of all PV energy produced by the system.
- Name
solar_direct_usage- Type
- array
- Description
Solar energy directly consumed by the load in kW. PV power that immediately meets on-site demand without storage or grid interaction.
- Name
solar_exported_to_grid- Type
- array
- Description
Solar energy exported to the grid in kW. Excess PV generation sent back to the utility network (often sold at feed-in tariff rates).
- Name
solar_stored_in_battery- Type
- array
- Description
Solar energy sent to battery storage in kW. PV power used to charge the battery for later use.
- Name
solar_curtailment- Type
- array
- Description
Solar energy curtailed (wasted) in kW. PV generation that couldn't be used due to system constraints (battery full, grid export limits, etc.).
- Name
grid_purchase- Type
- array
- Description
Grid electricity consumed by the load in kW. Energy purchased from the utility to meet demand when PV and battery are insufficient.
- Name
grid_purchase_baseline- Type
- array
- Description
Grid electricity that would be consumed in "Business As Usual" scenario (without the optimized system) in kW. Used for comparison to show savings.
- Name
grid_battery_charging- Type
- array
- Description
Grid electricity used to charge the battery in kW. Occurs when grid charging is economically advantageous (e.g., cheap off-peak rates with dynamic pricing).
- Name
battery_state_of_charge- Type
- array
- Description
Battery state of charge (SOC) statistics for each interval. Each element contains:
- Name
min- Type
- number
- Description
Minimum SOC percentage (0-100) during this interval.
- Name
max- Type
- number
- Description
Maximum SOC percentage (0-100) during this interval.
- Name
average- Type
- number
- Description
Average SOC percentage (0-100) during this interval.
Returns empty objects
{min: 0, max: 0, average: 0}if no battery is present in the system.
- Name
battery_state_of_charge_hourly- Type
- array
- Description
Granular hourly SOC data for the entire simulation period (8760 values for a year). Only included when
extended=true. Useful for detailed battery behavior analysis but can be large. Empty array if no battery orextended=false.
- Name
tariff_type- Type
- string
- Description
Type of electricity tariff used in the optimization:
"flat"or"dynamic".
- Name
dynamic_tariffs- Type
- array
- Description
Electricity tariff rates for each interval (only populated if
tariff_type="dynamic"). Each element contains:- Name
min- Type
- number
- Description
Minimum tariff rate (€/kWh) during this interval.
- Name
max- Type
- number
- Description
Maximum tariff rate (€/kWh) during this interval.
- Name
average- Type
- number
- Description
Average tariff rate (€/kWh) during this interval.
Empty array or zero values if
tariff_type="flat".
- Name
labels- Type
- array
- Description
Human-readable labels for each data point. Format depends on
interval:day: Hour labels like"00:00","01:00", ...,"23:00"(24 entries)week: Day names or dates (7 entries)month: Date labels (28-31 entries)year: Month names (12 entries)
- Name
interval_type- Type
- string
- Description
Echo of the requested interval type:
"day","week","month", or"year".
- Name
start_date- Type
- string
- Description
ISO 8601 timestamp of the period start date.
- Name
end_date- Type
- string
- Description
ISO 8601 timestamp of the period end date.
Understanding Energy Flows
The chart data reveals how energy flows through your system:
- Solar Production:
solar_total_generationshows when and how much your panels generate - Direct Consumption:
solar_direct_usageshows solar energy immediately consumed - Battery Charging:
solar_stored_in_batteryshows when excess solar charges the battery - Grid Export:
solar_exported_to_gridshows when you're sending power back to the grid - Grid Import:
grid_purchaseshows when you're buying from the grid - Battery State:
battery_state_of_chargeshows how full your battery is over time
Energy Balance Equation:
site_consumption = solar_direct_usage + grid_purchase + (battery discharge)
solar_total_generation = solar_direct_usage + solar_stored_in_battery + solar_exported_to_grid + solar_curtailment
Visualization Tip: Use this data to create stacked area charts showing energy sources (solar, battery, grid)
and energy destinations (consumption, battery, grid export). The labels array provides x-axis values.
Request
# Get today's hourly data (default)
curl -X GET 'https://api.enhub.nl/v1/scan/chart?run-uuid=123e4567-e89b-12d3-a456-426614174000' \
-H "Authorization: Bearer {token}"
# Get specific day with extended battery data
curl -X GET 'https://api.enhub.nl/v1/scan/chart?run-uuid=123e4567-e89b-12d3-a456-426614174000&startDate=2024-10-14&interval=day&extended=true' \
-H "Authorization: Bearer {token}"
# Get monthly aggregated data
curl -X GET 'https://api.enhub.nl/v1/scan/chart?run-uuid=123e4567-e89b-12d3-a456-426614174000&interval=month&startDate=2024-10-01' \
-H "Authorization: Bearer {token}"
Response
{
"site_consumption": [
0.085, 0.084, 0.050, 0.079, 0.372, 0.414,
0.560, 0.357, 0.362, 0.429, 0.417, 0.455,
0.513, 0.398, 0.383, 0.420, 0.265, 0.592,
1.111, 0.785, 0.553, 0.273, 0.233, 0.179
],
"solar_total_generation": [
0, 0, 0, 0, 0, 0, 0, 0,
0.018, 0.121, 0.238, 0.225, 0.580, 0.651,
0.715, 0.421, 0.292, 0.020, 0.004, 0,
0, 0, 0, 0
],
"solar_direct_usage": [
0, 0, 0, 0, 0, 0, 0, 0,
0.018, 0.121, 0.238, 0.225, 0.513, 0.398,
0.383, 0.420, 0.265, 0.020, 0.004, 0,
0, 0, 0, 0
],
"solar_exported_to_grid": [
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0.067, 0.253, 0.332, 0.001,
0.027, 0, 0, 0, 0, 0, 0, 0
],
"solar_stored_in_battery": [
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0
],
"solar_curtailment": [
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0
],
"grid_purchase": [
0.085, 0.084, 0.050, 0.079, 0.372, 0.414,
0.560, 0.357, 0.344, 0.308, 0.179, 0.230,
0, 0, 0, 0, 0, 0.573, 1.107, 0.785,
0.553, 0.273, 0.233, 0.179
],
"grid_purchase_baseline": [
0.085, 0.084, 0.050, 0.079, 0.372, 0.414,
0.560, 0.357, 0.362, 0.429, 0.417, 0.455,
0.513, 0.398, 0.383, 0.420, 0.265, 0.592,
1.111, 0.785, 0.553, 0.273, 0.233, 0.179
],
"grid_battery_charging": [
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0
],
"battery_state_of_charge": [
{"min": 0, "max": 0, "average": 0},
{"min": 0, "max": 0, "average": 0},
{"min": 0, "max": 0, "average": 0},
{"min": 0, "max": 0, "average": 0},
{"min": 0, "max": 0, "average": 0},
{"min": 0, "max": 0, "average": 0},
{"min": 0, "max": 0, "average": 0},
{"min": 0, "max": 0, "average": 0},
{"min": 0, "max": 0, "average": 0},
{"min": 0, "max": 0, "average": 0},
{"min": 0, "max": 0, "average": 0},
{"min": 0, "max": 0, "average": 0},
{"min": 0, "max": 0, "average": 0},
{"min": 0, "max": 0, "average": 0},
{"min": 0, "max": 0, "average": 0},
{"min": 0, "max": 0, "average": 0},
{"min": 0, "max": 0, "average": 0},
{"min": 0, "max": 0, "average": 0},
{"min": 0, "max": 0, "average": 0},
{"min": 0, "max": 0, "average": 0},
{"min": 0, "max": 0, "average": 0},
{"min": 0, "max": 0, "average": 0},
{"min": 0, "max": 0, "average": 0},
{"min": 0, "max": 0, "average": 0}
],
"battery_state_of_charge_hourly": [],
"tariff_type": "dynamic",
"dynamic_tariffs": [
{"min": 0.18659, "max": 0.18659, "average": 0.18659},
{"min": 0.19657, "max": 0.19657, "average": 0.19657},
{"min": 0.19924, "max": 0.19924, "average": 0.19924},
{"min": 0.19150, "max": 0.19150, "average": 0.19150},
{"min": 0.19875, "max": 0.19875, "average": 0.19875},
{"min": 0.22205, "max": 0.22205, "average": 0.22205},
{"min": 0.25212, "max": 0.25212, "average": 0.25212},
{"min": 0.23420, "max": 0.23420, "average": 0.23420},
{"min": 0.20778, "max": 0.20778, "average": 0.20778},
{"min": 0.18531, "max": 0.18531, "average": 0.18531},
{"min": 0.15626, "max": 0.15626, "average": 0.15626},
{"min": 0.11547, "max": 0.11547, "average": 0.11547},
{"min": 0.11043, "max": 0.11043, "average": 0.11043},
{"min": 0.11041, "max": 0.11041, "average": 0.11041},
{"min": 0.11950, "max": 0.11950, "average": 0.11950},
{"min": 0.16171, "max": 0.16171, "average": 0.16171},
{"min": 0.20133, "max": 0.20133, "average": 0.20133},
{"min": 0.22451, "max": 0.22451, "average": 0.22451},
{"min": 0.24444, "max": 0.24444, "average": 0.24444},
{"min": 0.22400, "max": 0.22400, "average": 0.22400},
{"min": 0.20156, "max": 0.20156, "average": 0.20156},
{"min": 0.19947, "max": 0.19947, "average": 0.19947},
{"min": 0.18937, "max": 0.18937, "average": 0.18937},
{"min": 0.18288, "max": 0.18288, "average": 0.18288}
],
"labels": [
"00:00", "01:00", "02:00", "03:00", "04:00", "05:00",
"06:00", "07:00", "08:00", "09:00", "10:00", "11:00",
"12:00", "13:00", "14:00", "15:00", "16:00", "17:00",
"18:00", "19:00", "20:00", "21:00", "22:00", "23:00"
],
"interval_type": "day",
"start_date": "2024-10-14T00:00:00Z",
"end_date": "2024-10-15T00:00:00Z"
}
Response
{
"error": "Invalid interval. Must be one of: day, week, month, year",
"message": null
}
Response
{
"error": "Failed to get chart data",
"message": null
}
Get scan result
Retrieve the full report results for a completed scan. The scan must have finished processing before results are available.
Scan must be completed: This endpoint only returns results when the scan status is "optimal".
Use the Check scan status endpoint or WebSocket Connection to monitor scan progress before calling this endpoint.
Query Parameters
- Name
run-uuid- Type
- string
- Required
- required
- Description
The unique identifier returned when the scan was created. Use this to fetch the results of a specific scan.
Response Fields
- Name
advice- Type
- boolean
- Description
Whether personalized advice is available for this scan.
- Name
max_years- Type
- number
- Description
Maximum analysis timeframe in years (typically 25 years for solar investments).
- Name
investment_costs- Type
- number
- Description
Total upfront investment cost in euros (€) for the recommended system.
- Name
self_sufficiency_pct- Type
- number
- Description
Energy self-sufficiency percentage (0-1). Indicates what portion of energy consumption is met by own generation.
- Name
payback_years- Type
- number
- Description
Payback period in years. Time until cumulative savings equal the initial investment.
- Name
yearly_savings- Type
- number
- Description
Average annual savings in euros (€) from the energy system.
- Name
trees_saved- Type
- number
- Description
Equivalent number of trees planted based on CO₂ savings (environmental impact metric).
- Name
co2_saved_in_tonnes- Type
- number
- Description
Total CO₂ emissions saved in metric tonnes over the analysis period.
- Name
npv- Type
- number
- Description
Net Present Value (NPV) in euros (€). Total financial value considering time value of money.
- Name
current_elec_usage- Type
- number
- Description
Current annual electricity usage in kWh before any system changes.
- Name
new_elec_usage- Type
- number
- Description
Projected annual electricity usage in kWh with the recommended system.
- Name
has_solar_panels_currently- Type
- boolean
- Description
Whether the site currently has solar panels installed.
- Name
has_or_wants_battery_currently- Type
- boolean
- Description
Whether the site currently has or wants battery storage.
- Name
wants_new_solar_panels- Type
- boolean
- Description
Whether new solar panels are being considered in the optimization.
- Name
current_solar_panels- Type
- array
- Description
Array of currently installed solar panel configurations.
- Name
power_in_wp- Type
- number
- Description
Power rating per panel in watts-peak (Wp).
- Name
amount- Type
- number
- Description
Number of panels in this configuration.
- Name
tilt- Type
- number
- Description
Tilt angle in degrees (0° = horizontal, 90° = vertical).
- Name
azimuth- Type
- number
- Description
Azimuth angle in degrees (180° = south, 90° = east, 270° = west, 0° = north).
- Name
losses- Type
- number
- Description
System losses as decimal (e.g., 0.14 = 14% losses).
- Name
name- Type
- string
- Description
Identifier for this solar panel configuration.
- Name
new_solar_panels- Type
- array
- Description
Array of newly recommended solar panel configurations (same structure as
current_solar_panels).
- Name
total_solar_panels- Type
- array
- Description
Combined array of all solar panels (existing + new) after optimization (same structure as
current_solar_panels).
- Name
battery- Type
- object
- Optional
- optional
- Description
Battery storage configuration if included in the optimization.
nullif no battery.- Name
electric_storage_power_in_kw- Type
- number
- Description
Optimal battery power capacity in kilowatts (kW).
- Name
elecitric_storage_capacity_in_kwh- Type
- number
- Description
Optimal battery energy capacity in kilowatt-hours (kWh).
- Name
created_at- Type
- string
- Description
ISO 8601 timestamp when the scan was created (e.g., "2024-10-14T12:00:00Z").
- Name
latitude- Type
- number
- Description
Geographic latitude of the site.
- Name
longitude- Type
- number
- Description
Geographic longitude of the site.
- Name
formatted_address- Type
- string
- Optional
- optional
- Description
Human-readable address of the site (if available).
- Name
goal- Type
- string
- Description
Optimization goal used for this scan. One of:
self-sufficiency,payback-time, orcontract-comparison.
- Name
tariff_type- Type
- string
- Description
Type of electricity tariff used:
flatordynamic.
- Name
has_error- Type
- boolean
- Description
Whether an error occurred during scan processing.
- Name
user- Type
- string
- Description
User ID who created the scan.
- Name
user_email- Type
- string
- Description
Email address of the user who created the scan.
- Name
load_profile- Type
- string
- Description
The load profile used for this scan. Either a standard profile name (
"standard","coupleBothAtWork","couple1home1work","3kidsbothwork") or a custom profile ID ifuse_custom_load_profileistrue.
- Name
use_custom_load_profile- Type
- boolean
- Description
Whether a custom load profile was used for this scan. When
true, theload_profilefield contains a custom profile ID. Whenfalse, it contains a standard profile name.
Request
curl -X GET 'https://api.enhub.nl/v1/scan?run-uuid=123e4567-e89b-12d3-a456-426614174000' \
-H "Authorization: Bearer {token}"
Response
{
"advice": true,
"max_years": 25,
"investment_costs": 12500.50,
"self_sufficiency_pct": 0.78,
"payback_years": 8.5,
"yearly_savings": 1470.25,
"trees_saved": 142,
"co2_saved_in_tonnes": 32.5,
"npv": 18750.00,
"current_elec_usage": 5000,
"new_elec_usage": 1100,
"has_solar_panels_currently": false,
"has_or_wants_battery_currently": true,
"wants_new_solar_panels": true,
"current_solar_panels": [],
"new_solar_panels": [
{
"power_in_wp": 430,
"amount": 8,
"tilt": 35,
"azimuth": 180,
"losses": 0.14,
"name": "roof_south"
}
],
"total_solar_panels": [
{
"power_in_wp": 430,
"amount": 8,
"tilt": 35,
"azimuth": 180,
"losses": 0.14,
"name": "roof_south"
}
],
"battery": {
"electric_storage_power_in_kw": 5.0,
"elecitric_storage_capacity_in_kwh": 10.0
},
"created_at": "2024-10-14T12:00:00Z",
"latitude": 52.1015441,
"longitude": 5.1779992,
"formatted_address": "Amsterdam, Netherlands",
"goal": "self-sufficiency",
"tariff_type": "flat",
"has_error": false,
"user": "user123",
"user_email": "user@example.com",
"load_profile": "coupleBothAtWork",
"use_custom_load_profile": false
}
Response
{
"error": "scan not found or not accessible",
"message": "<REASON OR MESSAGE>"
}
Response
{
"error": "failed to get job result",
"message": "Scan is not completed yet"
}
Response
{
"error": "failed to get job result",
"message": "<REASON OR MESSAGE>"
}