Windnavigator API Documentation
Overview
This documentation covers the unified Python implementation for accessing UL Renewables API endpoints, specifically the COMPASS stats and Global Reanalysis services.
API Configuration
API_KEY = 'your-api-key-here'
API_URL = 'https://ul-renewables.com/api'
Authentication
All requests require a valid API key passed in the request payload under the key
parameter.
COMPASS Stats API
Description
The COMPASS stats endpoint provides comprehensive wind resource statistics for a specific location and height.
Request Method
POST request to https://ul-renewables.com/api
Request Parameters
Parameter | Type | Required | Description |
---|---|---|---|
key | string | Yes | Your API authentication key |
product | string | Yes | Must be "stats" for statistical data |
latitude | float | Yes | Latitude coordinate (-90 to 90) |
longitude | float | Yes | Longitude coordinate (-180 to 180) |
height | integer | Yes | Hub height in meters |
Example Request
compass_payload = {
"key": "your-api-key",
"product": "stats",
"latitude": 36.12361,
"longitude": -95.37542,
"height": 250,
}
Response Format
The COMPASS stats API returns a JSON object with comprehensive wind resource data:
{
"elevation": 189.9,
"roughness": 0.045,
"ghi": 1660.699951171875,
"hubheight": 250,
"windSpeed": 9.06,
"windShear": 0.254,
"weibullA": 10.22,
"weibullK": 2.035,
"temperature": 13.3,
"airDensity": 1.161,
"meanPowerDensity": 809.9,
"rose": [0.075, 0.083, 0.051, 0.038, 0.025, 0.029, 0.052, 0.158, 0.251, 0.083, 0.038, 0.018, 0.012, 0.016, 0.023, 0.049],
"monthly": [10.35, 10.07, 9.91, 10.6, 9.38, 7.23, 6.71, 7.67, 7.06, 9.32, 10.47, 10.01],
"latitude": 36.12361,
"longitude": -95.37542
}
Response Fields Description
Field | Unit | Description |
---|---|---|
elevation | meters | Ground elevation above sea level |
roughness | - | Surface roughness coefficient |
ghi | kWh/m²/year | Global Horizontal Irradiance (annual) |
hubheight | meters | Requested hub height |
windSpeed | m/s | Mean annual wind speed |
windShear | - | Wind shear exponent |
weibullA | m/s | Weibull scale parameter |
weibullK | - | Weibull shape parameter |
Field | Unit | Description |
---|---|---|
temperature | °C | Mean annual temperature |
airDensity | kg/m³ | Mean air density |
meanPowerDensity | W/m² | Mean power density |
rose | - | Wind rose data (16 directional bins) |
monthly | m/s | Monthly average wind speeds (Jan-Dec) |
latitude | degrees | Requested latitude |
longitude | degrees | Requested longitude |
Global Reanalysis API
Description
The Global Reanalysis endpoint provides historical time series meteorological data from various reanalysis datasets.
Request Method
POST request to https://ul-renewables.com/api
Available Datasets
ERA5-100
ERA5 reanalysis at 100m height with high temporal resolution
ERA5-10
ERA5 reanalysis at 10m height with high temporal resolution
MERRA2-50
MERRA-2 reanalysis at 50m height with high spatial resolution
Request Parameters
Parameter | Type | Required | Description |
---|---|---|---|
key | string | Yes | Your API authentication key |
product | string | Yes | Must be "reanalysis" for time series data |
latitude | float | Yes | Latitude coordinate (-90 to 90) |
longitude | float | Yes | Longitude coordinate (-180 to 180) |
dataset | string | Yes | One of: era5-100, era5-10, merra2-50 |
Example Request
reanalysis_payload = {
'key': 'your-api-key',
'latitude': 39.38832449859204,
'longitude': -97.63412475585938,
'dataset': 'era5-100',
'product': 'reanalysis',
}
Response Format
The Global Reanalysis API returns a CSV time series file containing historical meteorological data with comprehensive metadata headers.
Example Response Structure:
ERA5 data downloaded from Windnavigator on 2025-07-07 11:09:19 EDT
URL: https://windnavigator.ul-renewables.com
Data set: ERA5 (1979-01-01T00:00:00Z - 2025-06-15T23:00:00Z)
Source: European Centre for Medium-Range Weather Forecasts
Provider: UL Services Group LLC
Latitude: 39.388324
Longitude: -97.634125
Height: 100m
Each time stamp indicates the beginning of a time step.
UL Services Group LLC provides this data as-is from source and does not guarantee its accuracy.
Date/time [UTC],Speed_100m [m/s],Direction_100m [degrees],Temperature_2m [degrees C],Pressure_0m [kPa]
1979-01-01T00:00:00,8.08712,350.31674,-13.28293,97.38020
1979-01-01T01:00:00,8.34000,355.27872,-13.28602,97.43256
1979-01-01T02:00:00,8.59824,1.43736,-13.37751,97.46263
...
Response Components
Header Information
- • Download timestamp and source URL
- • Dataset name and temporal coverage
- • Data source and provider information
- • Exact coordinates and measurement height
- • Data quality disclaimer
Data Columns
Column | Unit | Description |
---|---|---|
Date/time [UTC] | ISO 8601 | Timestamp in UTC |
Speed_100m [m/s] | m/s | Wind speed at height |
Direction_100m [degrees] | degrees | Wind direction |
Temperature_2m [degrees C] | °C | Air temperature |
Pressure_0m [kPa] | kPa | Surface pressure |
Data Processing Example
import pandas as pd
from io import StringIO
# After getting the response from Global Reanalysis API
if response.status_code == 200:
# Skip header lines and read CSV data
csv_data = response.text
# Find where the actual CSV data starts (after the header comments)
lines = csv_data.split('\n')
csv_start = 0
for i, line in enumerate(lines):
if line.startswith('Date/time'):
csv_start = i
break
# Read the CSV data into a pandas DataFrame
csv_content = '\n'.join(lines[csv_start:])
df = pd.read_csv(StringIO(csv_content))
# Convert datetime column
df['Date/time [UTC]'] = pd.to_datetime(df['Date/time [UTC]'])
# Now you can analyze the time series data
print(f"Data range: {df['Date/time [UTC]'].min()} to {df['Date/time [UTC]'].max()}")
print(f"Mean wind speed: {df['Speed_100m [m/s]'].mean():.2f} m/s")
print(f"Total records: {len(df)}")
Temporal Coverage
ERA5 Datasets
1979-01-01 to near-present (updated regularly)
MERRA-2 Datasets
1980-01-01 to near-present (updated regularly)
Resolution: Hourly data for all datasets
Time zone: All timestamps are in UTC
Code Implementation
Main Function
import requests
import json
# API Configuration
API_KEY = 'your-api-key-here'
API_URL = 'https://ul-renewables.com/api'
# Common headers
headers = {
'Content-Type': 'application/json'
}
def make_api_request(payload, request_type):
"""Make API request and handle response"""
print(f"\n--- {request_type} REQUEST ---")
print(f"Payload: {json.dumps(payload, indent=2)}")
response = requests.post(API_URL, headers=headers, json=payload)
if response.status_code == 200:
print(f"✓ Success: {response.status_code}")
print(f"Response: {response.text[:1000]}")
return response.json() if response.text else None
else:
print(f"✗ Error: {response.status_code} - {response.text}")
return None
# 1. COMPASS STATS REQUEST
print("="*60)
print("TESTING COMPASS STATS DATA")
print("="*60)
compass_payload = {
"key": API_KEY,
"product": "stats",
"latitude": 36.12361,
"longitude": -95.37542,
"height": 250,
}
compass_result = make_api_request(compass_payload, "COMPASS STATS")
# 2. GLOBAL REANALYSIS REQUEST
print("\n" + "="*60)
print("TESTING GLOBAL REANALYSIS DATA")
print("="*60)
print("Available datasets: era5-100, era5-10, merra2-50")
reanalysis_payload = {
'key': API_KEY,
'latitude': 39.38832449859204,
'longitude': -97.63412475585938,
'dataset': 'era5-100',
'product': 'reanalysis',
}
reanalysis_result = make_api_request(reanalysis_payload, "GLOBAL REANALYSIS")
# 3. OPTIONAL: Test multiple datasets
print("\n" + "="*60)
print("TESTING MULTIPLE REANALYSIS DATASETS")
print("="*60)
datasets = ['era5-100', 'era5-10', 'merra2-50']
for dataset in datasets:
multi_payload = {
'key': API_KEY,
'latitude': 39.38832449859204,
'longitude': -97.63412475585938,
'dataset': dataset,
'product': 'reanalysis',
}
print(f"\nTesting dataset: {dataset}")
result = make_api_request(multi_payload, f"REANALYSIS - {dataset.upper()}")
print("\n" + "="*60)
print("API TESTING COMPLETE")
print("="*60)
Error Handling
HTTP Status Codes
Checks for successful responses (200)
Response Validation
Handles both JSON and file responses
Error Logging
Provides detailed error information
Usage Examples
Single COMPASS Request
compass_result = make_api_request(compass_payload, "COMPASS STATS")
if compass_result:
wind_speed = compass_result['windSpeed']
power_density = compass_result['meanPowerDensity']
Multiple Dataset Testing
datasets = ['era5-100', 'era5-10', 'merra2-50']
for dataset in datasets:
payload['dataset'] = dataset
result = make_api_request(payload, f"REANALYSIS - {dataset.upper()}")
Troubleshooting
Common Issues
❌ Invalid API Key
Ensure your API key is correct and active
⚠️ Coordinate Errors
Verify latitude/longitude are within valid ranges
📍 Dataset Availability
Check that the requested dataset covers your location
🌐 Network Timeouts
Implement retry logic for network issues
HTTP Response Codes
Code | Status | Description | Action |
---|---|---|---|
200 | Success | Request completed successfully | Process the response data |
400 | Bad Request | Invalid parameters in request | Check parameter format and values |
401 | Unauthorized | Invalid or missing API key | Verify API key is correct and active |
404 | Not Found | Invalid endpoint URL | Check the API endpoint URL |
500 | Server Error | Internal server error | Retry request or contact support |