pvnodepvnode
  • pvnode.com
  • Studio
  • Pricing
  • Deutsch
  • English
  • API Reference
Product
  • Studio
  • API Documentation
  • API Reference
  • Pricing
Resources
  • Quickstart
  • Integrations
Legal
  • Imprint
  • Privacy
  • Terms
  • Licenses
pvnodepvnode

© 2026 pvnode. All rights reserved.

linkedin
Information
Forecast
    Get forecast for a sitegetGet forecast without a saved sitepost
Historical
    Get historical data for a sitegetGet historical data without a saved sitepost
Sites
    List all sitesgetCreate a sitepostGet a sitegetDelete a sitedeleteUpdate a sitepatchRestore a sitepost
V1 API (legacy)
    YieldgetSystemgetHistorygetForecastgetRecentget
Schemas
powered by Zudoku
pvnode API
pvnode API

Forecast


Get forecast for a site

GET
https://api.pvnode.com
/v2/forecast/{site_id}

Returns a PV power forecast for a saved site.

Uses the site's stored location, strings, and configuration. Timestamps are in the site's local timezone (see timezone in the response). The response covers past_days days of archived forecast data followed by forecast_days days of forecast. Note that archived forecast data differs from historical data, which tends to be more accurate.

Get forecast for a site › path Parameters

site_id
​string · required

Get forecast for a site › query Parameters

forecast_days
​

Forecast horizon as days beyond today. 0 = today only, 1 = today + tomorrow, etc. If omitted, returns the maximum allowed by your plan. Hard-capped at 7 (8 days incl. today); further clamped to your plan's limit.

past_days
​integer · min: 0 · max: 30

Past days to include before today. Defaults to 0. Hard-capped at 30; further clamped to your plan's limit.

Default: 0
include
​string[]

Field groups to include in the response. Combine freely (?include=weather&include=irradiance). default = pv_power. Omit default to receive only the requested groups (e.g. weather data only). all returns every available field. strings adds a separate top-level strings array with per-string PV power (long format) — values is unaffected. variability adds a pv_power_min/pv_power_max band (~next 48h) to values and to each strings row; requires a plan with variability access and is never part of all.

Enum values:
default
all
weather
irradiance
clearsky
strings
variability
Default: ["default"]

Get forecast for a site › Headers

Authorization
​string · required

Bearer token. Format: Bearer YOUR_API_KEY

Default: Bearer YOUR_API_KEY

Get forecast for a site › Responses

Successful Response

ForecastResponse
site_id
​string · required
timezone
​string · required

IANA timezone of the timestamps, e.g. 'Europe/Berlin'.

included
​string[] · required

Groups included in this response.

​ForecastDaily[] · required
​ForecastValue[] · required
​

ISO 8601 timestamp of when this forecast was computed. Forecasts are recomputed at fixed slots per day (see your plan's forecast.updates_per_day); repeat requests within the same slot return this same cached result.

​

Per-string PV power and tilted irradiance (gti/gti_shaded) in long format (one row per timestep per string). Present only when include=strings (or all). Each row carries string_index (positional, always present) and, for saved sites, string_id (stable id — use it to correlate with a string's measurements). Loads directly into a DataFrame; pivot on string_index for wide format. values stays unaffected — total pv_power there is the sum across strings. Tilted irradiance lives here (not in values) because it is orientation-dependent and therefore per-string.

GET/v2/forecast/{site_id}
import requests url = "https://api.pvnode.com/v2/forecast/:site_id" headers = {"Authorization": "Bearer YOUR_API_KEY"} response = requests.get(url, headers=headers) print(response.text)
Example Responses
{ "site_id": "site_id", "timezone": "timezone", "computed_at": "string", "included": [ "string" ], "daily": [ { "date": "date", "pv_energy_kwh": 0, "temp_min": 0, "temp_max": 0, "weather_code": 0, "pv_energy_kwh_clearsky": 0, "pv_energy_kwh_min": 0, "pv_energy_kwh_max": 0, "partial": true } ], "values": [ { "timestamp": "timestamp", "pv_power": 0, "pv_power_min": 0, "pv_power_max": 0, "temp": 0, "weather_code": 0, "wind_speed": 0, "relative_humidity": 0, "precipitation_mm": 0, "snow_water_equivalent": 0, "ghi": 0, "dhi": 0, "bni": 0, "pv_power_clearsky": 0 } ], "strings": [ { "timestamp": "timestamp", "string_index": 0, "string_id": "string", "pv_power": 0, "pv_power_min": 0, "pv_power_max": 0, "gti": 0, "gti_shaded": 0 } ] }
json
application/json

Get forecast without a saved site

POST
https://api.pvnode.com
/v2/forecast/inline

Returns a PV power forecast without requiring a saved site.

Provide the location (latitude + longitude) and optionally strings and config inline. Useful for one-off queries or integrations where managing sites is not needed. Computed fresh on every call (no server-side caching) and counts against your monthly forecast quota.

Get forecast without a saved site › query Parameters

forecast_days
​

Forecast horizon as days beyond today. 0 = today only, 1 = today + tomorrow, etc. If omitted, returns the maximum allowed by your plan. Hard-capped at 7 (8 days incl. today); further clamped to your plan's limit.

past_days
​integer · min: 0 · max: 30

Past days to include before today. Defaults to 0. Hard-capped at 30; further clamped to your plan's limit.

Default: 0
include
​string[]

Field groups to include. See the site endpoint for details.

Enum values:
default
all
weather
irradiance
clearsky
strings
variability
Default: ["default"]

Get forecast without a saved site › Headers

Authorization
​string · required

Bearer token. Format: Bearer YOUR_API_KEY

Default: Bearer YOUR_API_KEY

Get forecast without a saved site › Request Body

Forecast request without a saved site. Minimum: latitude + longitude.
InlineForecastRequest
latitude
​number · min: -89.99 · max: 89.99 · required

Latitude of the site in decimal degrees (WGS84).

Example: 48.8566
longitude
​number · min: -179.99 · max: 179.99 · required

Longitude of the site in decimal degrees (WGS84).

Example: 2.3522
​

PV string definitions. Defaults to a single string (10 kWp, 180° orientation, 30° tilt) if omitted.

​

Site configuration overrides. Omitted fields fall back to current defaults.

Get forecast without a saved site › Responses

Successful Response

ForecastResponse
site_id
​string · required
timezone
​string · required

IANA timezone of the timestamps, e.g. 'Europe/Berlin'.

included
​string[] · required

Groups included in this response.

​ForecastDaily[] · required
​ForecastValue[] · required
​

ISO 8601 timestamp of when this forecast was computed. Forecasts are recomputed at fixed slots per day (see your plan's forecast.updates_per_day); repeat requests within the same slot return this same cached result.

​

Per-string PV power and tilted irradiance (gti/gti_shaded) in long format (one row per timestep per string). Present only when include=strings (or all). Each row carries string_index (positional, always present) and, for saved sites, string_id (stable id — use it to correlate with a string's measurements). Loads directly into a DataFrame; pivot on string_index for wide format. values stays unaffected — total pv_power there is the sum across strings. Tilted irradiance lives here (not in values) because it is orientation-dependent and therefore per-string.

POST/v2/forecast/inline
import requests url = "https://api.pvnode.com/v2/forecast/inline" payload = { "latitude": 48.8566, "longitude": 2.3522, "strings": [ { "slope": 0, "orientation": 0, "power_kw": 0.1, "gcr": 0, "near_field_shading": "string" } ], "config": { "modules": { "technology": "perc", "temperature_coefficient": -0.35, "installation_year": 1980 }, "mounting": { "type": "open", "height_above_ground": 0 }, "inverter": { "clip_max_percent": 120, "clip_min_percent": 0.1 }, "losses": { "cable": 0.015, "conversion": 0.025, "albedo": 0.15, "snow_slide": 0.3, "diffuse_model": "perez" }, "shading": { "use_terrain_horizon": True, "sky_obstruction": "string" }, "tracking": { "type": "fixed", "axis_azimuth": 180, "axis_tilt": 0, "max_angle": 90, "backtracking": True } } } headers = { "Content-Type": "application/json", "Authorization": "Bearer YOUR_API_KEY" } response = requests.post(url, json=payload, headers=headers) print(response.text)
Example Request Body
{ "latitude": 48.8566, "longitude": 2.3522, "strings": [ { "slope": 0, "orientation": 0, "power_kw": 0.1, "gcr": 0, "near_field_shading": "string" } ], "config": { "modules": { "technology": "perc", "temperature_coefficient": -0.35, "installation_year": 1980 }, "mounting": { "type": "open", "height_above_ground": 0 }, "inverter": { "clip_max_percent": 120, "clip_min_percent": 0.1 }, "losses": { "cable": 0.015, "conversion": 0.025, "albedo": 0.15, "snow_slide": 0.3, "diffuse_model": "perez" }, "shading": { "use_terrain_horizon": true, "sky_obstruction": "string" }, "tracking": { "type": "fixed", "axis_azimuth": 180, "axis_tilt": 0, "max_angle": 90, "backtracking": true } } }
json
Example Responses
{ "site_id": "site_id", "timezone": "timezone", "computed_at": "string", "included": [ "string" ], "daily": [ { "date": "date", "pv_energy_kwh": 0, "temp_min": 0, "temp_max": 0, "weather_code": 0, "pv_energy_kwh_clearsky": 0, "pv_energy_kwh_min": 0, "pv_energy_kwh_max": 0, "partial": true } ], "values": [ { "timestamp": "timestamp", "pv_power": 0, "pv_power_min": 0, "pv_power_max": 0, "temp": 0, "weather_code": 0, "wind_speed": 0, "relative_humidity": 0, "precipitation_mm": 0, "snow_water_equivalent": 0, "ghi": 0, "dhi": 0, "bni": 0, "pv_power_clearsky": 0 } ], "strings": [ { "timestamp": "timestamp", "string_index": 0, "string_id": "string", "pv_power": 0, "pv_power_min": 0, "pv_power_max": 0, "gti": 0, "gti_shaded": 0 } ] }
json
application/json

Historical