Weather Endpoint
Current conditions, hourly forecasts, and daily summaries in a single call.
/v1/weather/:locationLocation Parameter Formats
| Format | Example | Description |
|---|---|---|
| City name | london | Geocoded to coordinates automatically |
| Lat,Lon | 40.71,-74.01 | Decimal degrees (most precise) |
| ZIP code | 10001 | US ZIP codes, resolved via geocoding |
| Airport code | KJFK | ICAO or IATA airport identifiers |
| City,Country | paris,fr | Disambiguates common city names |
Query Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
hours | int | 48 | Hours of hourly forecast (max 384) |
days | int | 7 | Days of daily forecast (max 16) |
models | string | "best" | "best", "gfs", "ecmwf", "hrrr", "all" |
units | string | "metric" | "metric", "imperial", "si" |
fields | string | "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 Field | Imperial Field | Conversion |
|---|---|---|
temperature_c | temperature_f | °C → °F |
wind_speed_ms | wind_speed_mph | m/s → mph |
precipitation_mm | precipitation_in | mm → inches |
visibility_m | visibility_mi | meters → miles |
pressure_hpa | pressure_inHg | hPa → inHg |
elevation_m | elevation_ft | meters → feet |
Example Requests
curl "https://api.qanto.com/v1/weather/london?days=3&hours=72" \
-H "Authorization: Bearer sk_live_YOUR_KEY"curl "https://api.qanto.com/v1/weather/tokyo?days=16&hours=384&models=all" \
-H "Authorization: Bearer sk_live_YOUR_KEY"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
| Status | Code | Description |
|---|---|---|
| 400 | INVALID_LOCATION | Could not resolve the location parameter |
| 400 | INVALID_PARAMS | Invalid query parameter value (e.g. days=99) |
| 401 | UNAUTHORIZED | Missing or invalid API key |
| 404 | NOT_FOUND | Endpoint does not exist |
| 429 | RATE_LIMITED | Too many requests — check Retry-After header |
| 502 | UPSTREAM_ERROR | Weather data source temporarily unavailable |
Models Endpoint
List available weather models, their status, coverage, and accuracy metrics.
/v1/modelsNo 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
| Model | Type | Status |
|---|---|---|
| ECMWF AIFS | AI (operational) | Integration in progress |
| NOAA AIGFS | AI (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
| Field | Type | Description |
|---|---|---|
lat | number | Latitude in decimal degrees |
lon | number | Longitude in decimal degrees |
name | string | Human-readable location name |
elevation_m | number | Elevation in meters above sea level |
timezone | string | IANA timezone identifier (e.g. America/New_York) |
country | string | ISO 3166-1 alpha-2 country code |
current Object
| Field | Type | Unit | Description |
|---|---|---|---|
time | string | ISO 8601 | Observation timestamp |
temperature_c | number | °C | Air temperature at 2m |
feels_like_c | number | °C | Apparent temperature (wind chill / heat index) |
humidity_pct | number | % | Relative humidity |
wind_speed_ms | number | m/s | Wind speed at 10m |
wind_direction_deg | number | ° | Wind direction (0=N, 90=E, 180=S, 270=W) |
wind_gust_ms | number | m/s | Maximum wind gust |
cloud_cover_pct | number | % | Total cloud cover |
pressure_hpa | number | hPa | Mean sea level pressure |
visibility_m | number | m | Horizontal visibility |
dew_point_c | number | °C | Dew point temperature |
uv_index | number | index | UV index (0-11+) |
solar_irradiance_wm2 | number | W/m² | Global horizontal irradiance |
weather_code | number | WMO | WMO weather condition code |
weather_description | string | — | Human-readable condition |
source | string | — | Data source identifier |
hourly[] Fields
| Field | Type | Unit | Description |
|---|---|---|---|
time | string | ISO 8601 | Forecast hour timestamp |
temperature_c | number | °C | Forecasted temperature |
feels_like_c | number | °C | Apparent temperature |
humidity_pct | number | % | Relative humidity |
wind_speed_ms | number | m/s | Wind speed |
wind_direction_deg | number | ° | Wind direction |
precipitation_mm | number | mm | Precipitation amount |
precipitation_probability_pct | number | % | Probability of precipitation |
cloud_cover_pct | number | % | Cloud cover |
solar_irradiance_wm2 | number | W/m² | Solar irradiance |
weather_code | number | WMO | WMO condition code |
source | string | — | Model source |
daily[] Fields
| Field | Type | Unit | Description |
|---|---|---|---|
date | string | YYYY-MM-DD | Forecast date |
temperature_max_c | number | °C | Daily maximum temperature |
temperature_min_c | number | °C | Daily minimum temperature |
precipitation_sum_mm | number | mm | Total daily precipitation |
precipitation_probability_max_pct | number | % | Peak precipitation probability |
wind_speed_max_ms | number | m/s | Maximum wind speed |
sunrise | string | HH:MM | Sunrise time (local) |
sunset | string | HH:MM | Sunset time (local) |
uv_index_max | number | index | Maximum UV index |
heating_degree_days | number | °C·day | Heating degree days (base 18°C) |
cooling_degree_days | number | °C·day | Cooling degree days (base 18°C) |
weather_code | number | WMO | Dominant weather code |
source | string | — | Model source |
meta Object
| Field | Type | Description |
|---|---|---|
credits_used | number | API credits consumed by this request |
models_used | string[] | List of model IDs used in the response |
generated_at | string | ISO 8601 timestamp of response generation |
cache_ttl_seconds | number | Seconds until this response is stale |
Imperial Field Name Mapping
When units=imperial, metric field names are replaced throughout the response:
| Metric | Imperial |
|---|---|
temperature_c | temperature_f |
feels_like_c | feels_like_f |
dew_point_c | dew_point_f |
temperature_max_c | temperature_max_f |
temperature_min_c | temperature_min_f |
wind_speed_ms | wind_speed_mph |
wind_gust_ms | wind_gust_mph |
wind_speed_max_ms | wind_speed_max_mph |
precipitation_mm | precipitation_in |
precipitation_sum_mm | precipitation_sum_in |
visibility_m | visibility_mi |
pressure_hpa | pressure_inHg |
elevation_m | elevation_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 Status | Code | Meaning | Action |
|---|---|---|---|
| 400 | BAD_REQUEST | Invalid request parameters | Check parameter values and types |
| 401 | UNAUTHORIZED | Missing or invalid API key | Verify your Authorization header |
| 404 | NOT_FOUND | Location not found or invalid endpoint | Check the URL and location format |
| 429 | RATE_LIMITED | Too many requests | Back off and retry after Retry-After seconds |
| 502 | UPSTREAM_ERROR | Weather data source temporarily down | Retry in 30-60 seconds with exponential backoff |
| 500 | INTERNAL_ERROR | Unexpected server error | Retry with exponential backoff; contact support if persistent |
Rate Limit Headers
| Header | Description |
|---|---|
X-RateLimit-Limit | Maximum requests allowed per window |
X-RateLimit-Remaining | Requests remaining in current window |
X-RateLimit-Reset | Unix timestamp when the window resets |
Retry-After | Seconds to wait before retrying (only on 429) |
Python Error Handling
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
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");
}