Getting Started
Authentication
To access Jua's API, you must create an API key in the developer portal. Include the key in your requests using the X-API-Key header.
X-API-Key: API_KEY_ID:API_KEY_SECRETQuery Data
1. Query a 3-day forecast for Zurich
curl -X GET "https://query.jua.ai/v1/forecast/\
?models=ept2\
&init_time=latest\
&latitude=47.37\
&longitude=8.54\
&variables=air_temperature_at_height_level_2m\
&variables=wind_speed_at_height_level_10m\
&max_prediction_timedelta=72\
-H "X-API-Key: YOUR_API_KEY" \
-H "Accept: application/json"import requests
url = "https://query.jua.ai/v1/forecast/"
headers = {
"X-API-Key": "YOUR_API_KEY",
"Accept": "application/json"
}
params = {
"models": "ept2",
"init_time": "latest",
"latitude": 47.37,
"longitude": 8.54,
"variables": [
"air_temperature_at_height_level_2m",
"wind_speed_at_height_level_10m"
],
"max_prediction_timedelta": 72, # hours
}
response = requests.get(url, headers=headers, params=params)
data = response.json()const url = new URL("https://query.jua.ai/v1/forecast/");
url.searchParams.append("models", "ept2");
url.searchParams.append("init_time", "latest");
url.searchParams.append("latitude", "47.37");
url.searchParams.append("longitude", "8.54");
url.searchParams.append("variables", "air_temperature_at_height_level_2m");
url.searchParams.append("variables", "wind_speed_at_height_level_10m");
url.searchParams.append("max_prediction_timedelta", "72");
const response = await fetch(url, {
method: "GET",
headers: {
"X-API-Key": "YOUR_API_KEY",
Accept: "application/json",
},
});
const data = await response.json();{
"model": [
"ept2",
"ept2",
71 more entries...
],
"init_time": ["2025-10-08T00:00:00Z", ...],
"prediction_timedelta": [0, 1, ...., 72],
"latitude": [...],
"longitude": [...],
"air_temperature_at_height_level_2m": [285.34, 285.91, ...],
"wind_speed_at_height_level_10m": [0.23, 0.51, ...]
}
2. Query market aggregated data
Query the average windspeed over Germany, weighted by wind energy production capacity
curl -X GET "https://query.jua.ai/v1/forecast/market-aggregate\
?models=ept2\
&init_time=2025-10-22T00:00:00Z\
&weighting=wind_capacity\
&market_zones=DE\
&variables=wind_speed_at_height_level_100m\
&max_prediction_timedelta=72\
&include_time=true \
-H "X-API-Key: YOUR_API_KEY" \
-H "Accept: application/json"import requests
url = "https://query.jua.ai/v1/forecast/market-aggregate"
headers = {
"X-API-Key": "YOUR_API_KEY",
"Accept": "application/json"
}
params = {
"models": "ept2",
"init_time": "2025-10-22T00:00:00Z",
"weighting": "wind_capacity",
"market_zones": ["DE"], # Germany
"variables": ["wind_speed_at_height_level_100m"],
"max_prediction_timedelta": 72, # hours
"include_time": True,
}
response = requests.get(url, headers=headers, params=params)
data = response.json()const url = new URL("https://query.jua.ai/v1/forecast/market-aggregate");
url.searchParams.append("models", "ept2");
url.searchParams.append("init_time", "2025-10-22T00:00:00Z");
url.searchParams.append("weighting", "wind_capacity");
url.searchParams.append("market_zones", "DE");
url.searchParams.append("variables", "wind_speed_at_height_level_100m");
url.searchParams.append("max_prediction_timedelta", "2880");
url.searchParams.append("include_time", "true");
const response = await fetch(url, {
method: "GET",
headers: {
"X-API-Key": "YOUR_API_KEY",
Accept: "application/json",
},
});
const data = await response.json();{
"model": [
"ept2",
"ept2",
71 more entries...
],
"init_time": ["2025-10-22T00:00:00Z", ...],
"prediction_timedelta": [0, 1, ...., 72],
"time": ["2025-10-22T00:00:00Z", "2025-10-22T01:00:00Z", ...],
"avg__wind_speed_at_height_level_100m": [0.23, 0.51, ...]
} To query wind speed at 100m your subscription must be Pro or higher
3. Using the general `data` endpoint (POST)
/data allows to make complex analytical queries, select regions, apply custom aggregations and much more.
The features include:
Making complex geospatial queries, supporting points, bounding boxes, polygons, market zones and countries
Querying multiple times at once, including historical time slices
Apply groupings and aggregations such as "hourly minimum and maximum temperature in Switzerland"
Apply solar & wind capacity or population density weighting to your queries
3.1 Request 3 months of historical data for Zurich for EPT2 and IFS
import requests
url = "https://query.jua.ai/v1/forecast/data"
headers = {
"X-API-Key": "YOUR_API_KEY",
"Content-Type": "application/json",
"Accept": "application/json"
}
params = {
# use arrow for larger requests, see query engine docs
"format": "json"
}
payload = {
"models": ["ept2", "ecmwf_ifs_single"],
"geo": {
"type": "point",
"value": [47.37, 8.54] # Zurich [latitude, longitude]
},
"variables": [
"air_temperature_at_height_level_2m",
"wind_speed_at_height_level_10m"
],
"init_time": {
"start": "2025-02-01T00:00:00Z",
"end": "2025-04-30T23:59:59Z"
},
"prediction_timedelta": {
"start": 0,
"end": 72
},
"order_by": ["model", "init_time", "time"],
"include_time": True,
"time_zone": "Europe/Zurich",
}
response = requests.post(url, headers=headers, params=params, json=payload)
data = response.json()const url = "https://query.jua.ai/v1/forecast/data?format=json";
const payload = {
models: ["ept2", "ecmwf_ifs_single"],
geo: {
type: "point",
value: [47.37, 8.54], // Zurich [latitude, longitude]
},
variables: [
"air_temperature_at_height_level_2m",
"wind_speed_at_height_level_10m",
],
init_time: {
start: "2025-02-01T00:00:00Z",
end: "2025-04-30T23:59:59Z",
},
prediction_timedelta: {
start: 0,
end: 72,
},
order_by: ["model", "init_time", "time"],
include_time: true,
time_zone: "Europe/Zurich",
};
const response = await fetch(url, {
method: "POST",
headers: {
"X-API-Key": "YOUR_API_KEY",
"Content-Type": "application/json",
Accept: "application/json",
},
body: JSON.stringify(payload),
});
const data = await response.json();{
"model": ["ept2", "ept2", ..., "ecmwf_ifs_single", "ecmwf_ifs_single", ...],
"init_time": [
"2025-02-01T00:00:00.000000Z",
"2025-02-01T00:00:00.000000Z",
...
"2025-02-01T00:00:00.000000Z",
"2025-02-01T00:00:00.000000Z",
...
],
"latitude": [47.37, 47.37, 47.37, 47.37, ...],
"longitude": [8.54, 8.54, 8.54, 8.54, ...],
"prediction_timedelta": [0, 1, ..., 0, 1, ...],
"time": [
"2025-02-01T00:00:00.000000Z",
"2025-02-01T01:00:00.000000Z",
...,
"2025-02-01T00:00:00.000000Z",
"2025-02-01T01:00:00.000000Z"
],
"air_temperature_at_height_level_2m": [275.5, 275.2, 276.1, 275.8, ...],
"wind_speed_at_height_level_10m": [2.3, 2.5, 2.4, 2.6]
}3.2 Compute population-weighted temperature average for a custom polygon region
import requests
url = "https://query.jua.ai/v1/forecast/data"
headers = {
"X-API-Key": "YOUR_API_KEY",
"Content-Type": "application/json",
"Accept": "application/json"
}
params = {
"format": "json"
}
payload = {
"models": ["ept2"],
"geo": {
"type": "polygon",
"value": [
# Custom polygon around a region
[45.82, 5.96],
[45.82, 10.49],
[47.81, 10.49],
[47.81, 5.96],
[45.82, 5.96]
]
},
"variables": ["air_temperature_at_height_level_2m"],
"init_time": "latest",
"prediction_timedelta": {
"start": 0,
"end": 72
},
"weighting": {
"type": "population"
},
"group_by": ["model", "init_time", "prediction_timedelta", "time"],
"aggregation": ["avg"],
"include_time": True,
"time_zone": "Europe/Zurich"
}
response = requests.post(url, headers=headers, params=params, json=payload)
data = response.json()const url = "https://query.jua.ai/v1/forecast/data?format=json";
const payload = {
models: ["ept2"],
geo: {
type: "polygon",
value: [
// Custom polygon around a region
[45.82, 5.96],
[45.82, 10.49],
[47.81, 10.49],
[47.81, 5.96],
[45.82, 5.96],
],
},
variables: ["air_temperature_at_height_level_2m"],
init_time: "latest",
prediction_timedelta: {
start: 0,
end: 48,
},
weighting: {
type: "population",
},
group_by: ["model", "init_time", "prediction_timedelta", "time"],
aggregation: ["avg"],
include_time: true,
time_zone: "Europe/Zurich",
};
const response = await fetch(url, {
method: "POST",
headers: {
"X-API-Key": "YOUR_API_KEY",
"Content-Type": "application/json",
Accept: "application/json",
},
body: JSON.stringify(payload),
});
const data = await response.json();{
"model": [
"ept2",
"ept2",
71 more entries...
],
"init_time": ["2025-10-08T00:00:00Z", ...],
"prediction_timedelta": [0, 1, ...., 72],
"avg__air_temperature_at_height_level_2m": [285.34, 285.91, ...],
}Key Differences Between GET and POST
Feature
GET Endpoints
POST /data Endpoint
Use Case
Simple queries
Complex queries, large datasets
Response Format
JSON only
JSON or Apache Arrow
Streaming
Not supported
Supported with Arrow format
Query Complexity
Limited parameters
Full query flexibility
URL Length
Limited by URL length
No practical limit
Aggregation
Limited (market-aggregate only)
Full aggregation support
Common Parameters
Time Parameters
init_time: Forecast initialization time (ISO 8601 format) or
"latest"for most recent forecastprediction_timedelta: Lead time in minutes from init_time
Single query:
{"start": 0, "end": 6}for 0-6 hoursOr use
min_prediction_timedeltaandmax_prediction_timedeltain GET requests
Location Parameters
Point:
{"type": "point", "value": [longitude, latitude], "method": "nearest"}Market Zone:
{"type": "market_zone", "value": ["DE", "FR"]}Country:
{"type": "country_key", "value": ["DE"]}Bounding Box:
{"type": "bbox", "value": [[lat_min, lon_min], [lat_max, lon_max]]}
Aggregation & Weighting
weighting:
wind_capacity,solar_capacity, orpopulationgroup_by: Columns to group by (e.g.,
["model", "init_time", "time"])
Credit Management
request_credit_limit: Maximum credits allowed for the request (prevents unexpectedly large charges)
Use
/costendpoint to estimate query cost before execution
Error Handling
Common HTTP status codes:
200: Success
400: Invalid parameters or response size exceeded
401: Missing or invalid API key
402: Insufficient credits
403: Model or variable not in subscription
Last updated