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
elevationmetersGround elevation above sea level
roughness-Surface roughness coefficient
ghikWh/m²/yearGlobal Horizontal Irradiance (annual)
hubheightmetersRequested hub height
windSpeedm/sMean annual wind speed
windShear-Wind shear exponent
weibullAm/sWeibull scale parameter
weibullK-Weibull shape parameter
Field Unit Description
temperature°CMean annual temperature
airDensitykg/m³Mean air density
meanPowerDensityW/m²Mean power density
rose-Wind rose data (16 directional bins)
monthlym/sMonthly average wind speeds (Jan-Dec)
latitudedegreesRequested latitude
longitudedegreesRequested 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 8601Timestamp in UTC
Speed_100m [m/s]m/sWind speed at height
Direction_100m [degrees]degreesWind direction
Temperature_2m [degrees C]°CAir temperature
Pressure_0m [kPa]kPaSurface 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