Weather Endpoint

Current conditions, hourly forecasts, and daily summaries in a single call.

GET/v1/weather/:location

Location Parameter Formats

FormatExampleDescription
City namelondonGeocoded to coordinates automatically
Lat,Lon40.71,-74.01Decimal degrees (most precise)
ZIP code10001US ZIP codes, resolved via geocoding
Airport codeKJFKICAO or IATA airport identifiers
City,Countryparis,frDisambiguates common city names

Query Parameters

ParameterTypeDefaultDescription
hoursint48Hours of hourly forecast (max 384)
daysint7Days of daily forecast (max 16)
modelsstring"best""best", "gfs", "ecmwf", "hrrr", "all"
unitsstring"metric""metric", "imperial", "si"
fieldsstring"standard""standard", "all", or comma-separated list

Example Response (Metric)

{
  "location": {
    "lat": 51.5074,
    "lon": -0.1278,
    "name": "London, England",
    "elevation_m": 11,
    "timezone": "Europe/London"
  },
  "current": {
    "time": "2026-03-15T12:00:00Z",
    "temperature_c": 11.4,
    "feels_like_c": 9.2,
    "humidity_pct": 72,
    "wind_speed_ms": 5.1,
    "wind_direction_deg": 230,
    "wind_gust_ms": 8.7,
    "cloud_cover_pct": 65,
    "pressure_hpa": 1018.2,
    "visibility_m": 12000,
    "dew_point_c": 6.8,
    "uv_index": 2,
    "solar_irradiance_wm2": 210,
    "weather_code": 3,
    "weather_description": "Overcast",
    "source": "nws_observation"
  },
  "hourly": [
    {
      "time": "2026-03-15T13:00:00Z",
      "temperature_c": 11.6,
      "feels_like_c": 9.4,
      "humidity_pct": 70,
      "wind_speed_ms": 5.3,
      "wind_direction_deg": 235,
      "precipitation_mm": 0,
      "precipitation_probability_pct": 15,
      "cloud_cover_pct": 60,
      "solar_irradiance_wm2": 230,
      "weather_code": 2,
      "source": "model_blend_gfs_ecmwf"
    }
  ],
  "daily": [
    {
      "date": "2026-03-15",
      "temperature_max_c": 13.1,
      "temperature_min_c": 6.2,
      "precipitation_sum_mm": 1.2,
      "precipitation_probability_max_pct": 35,
      "wind_speed_max_ms": 7.8,
      "sunrise": "06:12",
      "sunset": "18:08",
      "uv_index_max": 3,
      "heating_degree_days": 8.5,
      "cooling_degree_days": 0,
      "weather_code": 3,
      "source": "model_blend_gfs_ecmwf"
    }
  ],
  "meta": {
    "credits_used": 1,
    "models_used": ["gfs", "ecmwf_ifs"],
    "generated_at": "2026-03-15T12:02:00Z",
    "cache_ttl_seconds": 300
  }
}

Imperial Unit Changes

When units=imperial is set, field names and values change:

Metric FieldImperial FieldConversion
temperature_ctemperature_f°C → °F
wind_speed_mswind_speed_mphm/s → mph
precipitation_mmprecipitation_inmm → inches
visibility_mvisibility_mimeters → miles
pressure_hpapressure_inHghPa → inHg
elevation_melevation_ftmeters → feet

Example Requests

3-day London forecast
curl "https://api.qanto.com/v1/weather/london?days=3&hours=72" \
  -H "Authorization: Bearer sk_live_YOUR_KEY"
16-day extended forecast
curl "https://api.qanto.com/v1/weather/tokyo?days=16&hours=384&models=all" \
  -H "Authorization: Bearer sk_live_YOUR_KEY"
Minimal response (specific fields only)
curl "https://api.qanto.com/v1/weather/40.71,-74.01?fields=temperature_c,wind_speed_ms,precipitation_probability_pct" \
  -H "Authorization: Bearer sk_live_YOUR_KEY"

Error Codes

StatusCodeDescription
400INVALID_LOCATIONCould not resolve the location parameter
400INVALID_PARAMSInvalid query parameter value (e.g. days=99)
401UNAUTHORIZEDMissing or invalid API key
404NOT_FOUNDEndpoint does not exist
429RATE_LIMITEDToo many requests — check Retry-After header
502UPSTREAM_ERRORWeather data source temporarily unavailable

Models Endpoint

List available weather models, their status, coverage, and accuracy metrics.

GET/v1/models

No authentication required. This endpoint is public so developers can discover available models before signing up.

Example Response

{
  "models": [
    {
      "id": "gfs",
      "name": "NOAA GFS",
      "provider": "NOAA",
      "type": "physics",
      "resolution_km": 28,
      "forecast_hours": 384,
      "update_frequency_hours": 6,
      "coverage": "global",
      "status": "operational",
      "accuracy_rank": 3,
      "license": "public_domain",
      "description": "Global Forecast System — workhorse global model from NOAA."
    },
    {
      "id": "ecmwf_ifs",
      "name": "ECMWF IFS",
      "provider": "ECMWF",
      "type": "physics",
      "resolution_km": 28,
      "forecast_hours": 360,
      "update_frequency_hours": 6,
      "coverage": "global",
      "status": "operational",
      "accuracy_rank": 1,
      "license": "cc_by_4.0",
      "description": "Integrated Forecasting System — widely considered the world's best global forecast model."
    },
    {
      "id": "hrrr",
      "name": "NOAA HRRR",
      "provider": "NOAA",
      "type": "physics",
      "resolution_km": 3,
      "forecast_hours": 48,
      "update_frequency_hours": 1,
      "coverage": "conus",
      "status": "operational",
      "accuracy_rank": 1,
      "license": "public_domain",
      "description": "High-Resolution Rapid Refresh — 3km resolution, hourly updates, radar-assimilated. Best for US short-range."
    }
  ],
  "meta": {
    "total": 3,
    "generated_at": "2026-03-15T12:00:00Z"
  }
}

Model Details

NOAA GFS

The Global Forecast System is NOAA's primary global numerical weather prediction model. It produces forecasts out to 16 days (384 hours) at 28 km resolution, updated every 6 hours. GFS is the backbone of most free weather services and is public domain — no licensing restrictions.

ECMWF IFS

The Integrated Forecasting System from the European Centre for Medium-Range Weather Forecasts is widely considered the most accurate global forecast model. It provides 15-day forecasts at 28 km resolution. ECMWF opened its data under CC-BY-4.0 in October 2025, making it freely accessible for commercial use.

NOAA HRRR

The High-Resolution Rapid Refresh model runs at 3 km resolution with hourly updates, assimilating radar data in near real-time. It covers the continental US (CONUS) and is the gold standard for short-range (0-48 hour) forecasting. Its high resolution makes it ideal for hyperlocal applications like drone operations and construction planning.

Coming Soon

ModelTypeStatus
ECMWF AIFSAI (operational)Integration in progress
NOAA AIGFSAI (GraphCast-based)Integration in progress
NVIDIA Earth-2 (Atlas)AI (Apache 2.0)Planned Q2 2026

Response Schema

Complete field reference for the /v1/weather/:location endpoint.

Top-Level Structure

{
  "location": { ... },
  "current":  { ... },
  "hourly":   [ ... ],
  "daily":    [ ... ],
  "meta":     { ... }
}

location Object

FieldTypeDescription
latnumberLatitude in decimal degrees
lonnumberLongitude in decimal degrees
namestringHuman-readable location name
elevation_mnumberElevation in meters above sea level
timezonestringIANA timezone identifier (e.g. America/New_York)
countrystringISO 3166-1 alpha-2 country code

current Object

FieldTypeUnitDescription
timestringISO 8601Observation timestamp
temperature_cnumber°CAir temperature at 2m
feels_like_cnumber°CApparent temperature (wind chill / heat index)
humidity_pctnumber%Relative humidity
wind_speed_msnumberm/sWind speed at 10m
wind_direction_degnumber°Wind direction (0=N, 90=E, 180=S, 270=W)
wind_gust_msnumberm/sMaximum wind gust
cloud_cover_pctnumber%Total cloud cover
pressure_hpanumberhPaMean sea level pressure
visibility_mnumbermHorizontal visibility
dew_point_cnumber°CDew point temperature
uv_indexnumberindexUV index (0-11+)
solar_irradiance_wm2numberW/m²Global horizontal irradiance
weather_codenumberWMOWMO weather condition code
weather_descriptionstringHuman-readable condition
sourcestringData source identifier

hourly[] Fields

FieldTypeUnitDescription
timestringISO 8601Forecast hour timestamp
temperature_cnumber°CForecasted temperature
feels_like_cnumber°CApparent temperature
humidity_pctnumber%Relative humidity
wind_speed_msnumberm/sWind speed
wind_direction_degnumber°Wind direction
precipitation_mmnumbermmPrecipitation amount
precipitation_probability_pctnumber%Probability of precipitation
cloud_cover_pctnumber%Cloud cover
solar_irradiance_wm2numberW/m²Solar irradiance
weather_codenumberWMOWMO condition code
sourcestringModel source

daily[] Fields

FieldTypeUnitDescription
datestringYYYY-MM-DDForecast date
temperature_max_cnumber°CDaily maximum temperature
temperature_min_cnumber°CDaily minimum temperature
precipitation_sum_mmnumbermmTotal daily precipitation
precipitation_probability_max_pctnumber%Peak precipitation probability
wind_speed_max_msnumberm/sMaximum wind speed
sunrisestringHH:MMSunrise time (local)
sunsetstringHH:MMSunset time (local)
uv_index_maxnumberindexMaximum UV index
heating_degree_daysnumber°C·dayHeating degree days (base 18°C)
cooling_degree_daysnumber°C·dayCooling degree days (base 18°C)
weather_codenumberWMODominant weather code
sourcestringModel source

meta Object

FieldTypeDescription
credits_usednumberAPI credits consumed by this request
models_usedstring[]List of model IDs used in the response
generated_atstringISO 8601 timestamp of response generation
cache_ttl_secondsnumberSeconds until this response is stale

Imperial Field Name Mapping

When units=imperial, metric field names are replaced throughout the response:

MetricImperial
temperature_ctemperature_f
feels_like_cfeels_like_f
dew_point_cdew_point_f
temperature_max_ctemperature_max_f
temperature_min_ctemperature_min_f
wind_speed_mswind_speed_mph
wind_gust_mswind_gust_mph
wind_speed_max_mswind_speed_max_mph
precipitation_mmprecipitation_in
precipitation_sum_mmprecipitation_sum_in
visibility_mvisibility_mi
pressure_hpapressure_inHg
elevation_melevation_ft

Error Handling

All errors follow a consistent JSON format with actionable messages.

Error Response Format

{
  "error": {
    "code": "ERROR_CODE",
    "message": "Human-readable description of what went wrong.",
    "docs": "https://docs.qanto.com/errors#ERROR_CODE",
    "request_id": "req_abc123xyz"
  }
}

Error Codes

HTTP StatusCodeMeaningAction
400BAD_REQUESTInvalid request parametersCheck parameter values and types
401UNAUTHORIZEDMissing or invalid API keyVerify your Authorization header
404NOT_FOUNDLocation not found or invalid endpointCheck the URL and location format
429RATE_LIMITEDToo many requestsBack off and retry after Retry-After seconds
502UPSTREAM_ERRORWeather data source temporarily downRetry in 30-60 seconds with exponential backoff
500INTERNAL_ERRORUnexpected server errorRetry with exponential backoff; contact support if persistent

Rate Limit Headers

HeaderDescription
X-RateLimit-LimitMaximum requests allowed per window
X-RateLimit-RemainingRequests remaining in current window
X-RateLimit-ResetUnix timestamp when the window resets
Retry-AfterSeconds to wait before retrying (only on 429)

Python Error Handling

Python
import requests
import time

def get_weather(location, api_key, max_retries=3):
    url = f"https://api.qanto.com/v1/weather/{location}"
    headers = {"Authorization": f"Bearer {api_key}"}

    for attempt in range(max_retries):
        response = requests.get(url, headers=headers)

        if response.status_code == 200:
            return response.json()

        if response.status_code == 429:
            retry_after = int(response.headers.get("Retry-After", 5))
            print(f"Rate limited. Retrying in {retry_after}s...")
            time.sleep(retry_after)
            continue

        if response.status_code >= 500:
            wait = 2 ** attempt
            print(f"Server error {response.status_code}. Retrying in {wait}s...")
            time.sleep(wait)
            continue

        # Client error — don't retry
        error = response.json().get("error", {})
        raise Exception(
            f"API error {response.status_code}: "
            f"{error.get('code')} — {error.get('message')}"
        )

    raise Exception("Max retries exceeded")

JavaScript Error Handling

JavaScript
async function getWeather(location, apiKey, maxRetries = 3) {
  const url = `https://api.qanto.com/v1/weather/${location}`;

  for (let attempt = 0; attempt < maxRetries; attempt++) {
    const response = await fetch(url, {
      headers: { Authorization: `Bearer ${apiKey}` },
    });

    if (response.ok) {
      return response.json();
    }

    if (response.status === 429) {
      const retryAfter = parseInt(response.headers.get("Retry-After") || "5");
      console.log(`Rate limited. Retrying in ${retryAfter}s...`);
      await new Promise((r) => setTimeout(r, retryAfter * 1000));
      continue;
    }

    if (response.status >= 500) {
      const wait = Math.pow(2, attempt) * 1000;
      console.log(`Server error ${response.status}. Retrying in ${wait}ms...`);
      await new Promise((r) => setTimeout(r, wait));
      continue;
    }

    // Client error — don't retry
    const { error } = await response.json();
    throw new Error(`API error ${response.status}: ${error.code} — ${error.message}`);
  }

  throw new Error("Max retries exceeded");
}