Everything you need to integrate WeatherLens into your app.
All API requests require an API key. Pass it via header or query parameter:
# Header (recommended) curl -H "X-API-Key: wl_live_your_key" https://weatherlens.dev/api/v1/forecast?lat=28.38&lon=-81.57 # Query parameter curl "https://weatherlens.dev/api/v1/forecast?lat=28.38&lon=-81.57&key=wl_live_your_key"
Get your free API key at /dashboard, or create one programmatically via POST /keys.
| Plan | Daily | Per Minute | Forecast Days | Monthly | Annual |
|---|---|---|---|---|---|
| Free | 100 | 10 | 7 | $0 | $0 |
| Starter | 5,000 | 60 | 16 | $9/mo | $90/yr |
| Pro | 50,000 | 300 | 16 | $29/mo | $290/yr |
Daily limits reset at midnight UTC. When a limit is hit, the API returns 429 Too Many Requests with details about your usage and the reset time. Every response includes a usage object showing your current consumption.
https://weatherlens.dev/api/v1
All responses are JSON. Successful responses return HTTP 200 (or 201 for key creation). Errors include an error field with a human-readable message.
| Method | Endpoint | Description | Plan |
|---|---|---|---|
GET | /forecast | Weather forecasts up to 16 days | All |
GET | /climate | Climate normals (weighted averages) | All |
GET | /accuracy | Forecast accuracy scores | All |
GET | /historical | Observed historical weather (up to 365 days) | Pro |
GET | /keys | List your API keys | All |
POST | /keys | Create a new API key | All |
DELETE | /keys | Revoke an API key | All |
GET | /usage | Usage statistics | All |
Get weather forecasts for a location. Coordinates are snapped to 4 decimal places. New locations are auto-registered.
| Param | Type | Required | Description |
|---|---|---|---|
lat | number | Yes | Latitude (-90 to 90) |
lon | number | Yes | Longitude (-180 to 180) |
days | integer | No | Forecast days (default: 16 paid / 7 free, max: 16) |
curl -H "X-API-Key: YOUR_KEY" \
"https://weatherlens.dev/api/v1/forecast?lat=28.3772&lon=-81.5707&days=7"
{
"location": { "lat": 28.3772, "lon": -81.5707 },
"days": 7,
"forecast": [
{
"date": "2025-01-15",
"source": "nws",
"leadDays": 0,
"temperature": { "highF": 78, "lowF": 56, "avgF": 67 },
"precipitation": { "probabilityPct": 20, "amountIn": 0.02 },
"wind": {
"speedMph": 12,
"description": "E winds 8 to 12 mph",
"direction": "E"
},
"conditions": {
"code": 2,
"description": "Partly Cloudy",
"emoji": "⛅",
"forecast": "Partly cloudy with a 20% chance of showers"
},
"uvIndex": 6,
"humidityPct": 62,
"cloudCoverPct": 45,
"solarRadiation": { "dailyMj": 18.5, "unit": "MJ/m²" },
"confidence": 0.92
}
],
"meta": {
"sources": ["weatherlens", "nws", "open_meteo", "nasa_power"],
"strategy": "Proprietary multi-source blend with accuracy-weighted adjustments",
"updated": "2025-01-15T06:00:00Z"
},
"usage": { "today": 42, "limit": 100 }
}US locations (lat 24-50, lon -130 to -60) use the National Weather Service for days 1-7, blended with Open-Meteo for days 8-16. International locations use Open-Meteo exclusively. The source field on each day indicates which source provided the data.
Get climate normals (weighted historical averages) for a location.
| Param | Type | Required | Description |
|---|---|---|---|
lat | number | Yes | Latitude |
lon | number | Yes | Longitude |
date | string | No | YYYY-MM-DD (single or comma-separated range). Omit for all 366 days. |
curl -H "X-API-Key: YOUR_KEY" \
"https://weatherlens.dev/api/v1/climate?lat=28.38&lon=-81.57&date=2025-07-04"
{
"location": { "lat": 28.38, "lon": -81.57 },
"days": 1,
"method": "Proprietary weighted average (multi-year lookback with recency bias)",
"climate": [
{
"month": 7,
"day": 4,
"date": "07-04",
"temperature": { "highF": 92.3, "lowF": 74.1 },
"precipitation": { "avgInchesPerDay": 0.31, "avgHoursPerDay": 2.4 },
"conditions": {
"code": 80,
"description": "Rain showers: Slight",
"emoji": "🌦️"
},
"wind": { "avgMph": 7.8 },
"humidityPct": 73,
"uvIndex": 11.2,
"yearsSampled": 5
}
],
"usage": { "today": 43, "limit": 100 }
}Climate normals are computed weekly from 5 years of historical data with 15%/year recency weighting. The yearsSampled field indicates how many years of data contributed to each day.
Get forecast accuracy scores broken down by source, month, and lead-time bucket. New exact coordinates are queued for collection, and missing forecast-month buckets are hydrated on demand before the response returns.
| Param | Type | Required | Description |
|---|---|---|---|
lat | number | Yes | Latitude |
lon | number | Yes | Longitude |
month | integer | No | Filter by month (1-12) |
source | string | No | Filter by source (weatherlens, nws, open_meteo) |
curl -H "X-API-Key: YOUR_KEY" \
"https://weatherlens.dev/api/v1/accuracy?lat=28.38&lon=-81.57&month=1&source=nws"
{
"location": { "lat": 28.38, "lon": -81.57 },
"summary": {
"totalSamples": 248,
"weightedOverallScore": 82.4,
"methodology": "Weighted: temperature 40%, precipitation 35%, condition match 25%"
},
"accuracy": {
"1": {
"nws": {
"1day": { "samples": 31, "avgTempErrorF": 1.8, "avgPrecipErrorPct": 12, "conditionMatchPct": 91, "overallScore": 92.1, "lastUpdated": "2025-01-15" },
"2-3day": { "samples": 62, "avgTempErrorF": 2.9, "avgPrecipErrorPct": 18, "conditionMatchPct": 85, "overallScore": 86.3, "lastUpdated": "2025-01-15" },
"4-7day": { "samples": 93, "avgTempErrorF": 4.1, "avgPrecipErrorPct": 28, "conditionMatchPct": 72, "overallScore": 74.8, "lastUpdated": "2025-01-15" },
"8-16day":{ "samples": 62, "avgTempErrorF": 5.6, "avgPrecipErrorPct": 35, "conditionMatchPct": 61, "overallScore": 63.2, "lastUpdated": "2025-01-15" }
}
}
},
"usage": { "today": 44, "limit": 100 }
}Accuracy is measured by comparing archived forecast snapshots against observed actuals. For newly requested coordinates, WeatherLens performs a bounded cold-start bootstrap for the active forecast months using exact-coordinate historical data, then live samples take over as collection runs. Composite score: temperature 40% + precipitation 35% + condition match 25%. Results are grouped into lead-time buckets: 1day, 2-3day, 4-7day, 8-16day. Only buckets with ≥ 3 samples are included.
Get observed historical weather data. Pro only
| Param | Type | Required | Description |
|---|---|---|---|
lat | number | Yes | Latitude |
lon | number | Yes | Longitude |
start | string | Yes | Start date (YYYY-MM-DD) |
end | string | Yes | End date (YYYY-MM-DD, max 365 day span) |
curl -H "X-API-Key: YOUR_PRO_KEY" \
"https://weatherlens.dev/api/v1/historical?lat=28.38&lon=-81.57&start=2024-01-01&end=2024-01-03"
{
"location": { "lat": 28.38, "lon": -81.57 },
"source": "observed",
"period": { "start": "2024-01-01", "end": "2024-01-03" },
"data": [
{
"date": "2024-01-01",
"temperature": { "highF": 76.3, "lowF": 58.1 },
"precipitation": { "amountIn": 0.0 },
"conditions": { "code": 1 }
},
{
"date": "2024-01-02",
"temperature": { "highF": 79.5, "lowF": 61.2 },
"precipitation": { "amountIn": 0.12 },
"conditions": { "code": 61 }
}
],
"usage": { "today": 45, "limit": 50000 }
}Returns locally-stored observed actuals when available, with automatic fallback to Open-Meteo archive data. The source field will be "observed" or "open-meteo-archive". Returns 403 for non-Pro plans.
Manage your API keys programmatically. Maximum 5 keys per account.
| Body Field | Type | Required | Description |
|---|---|---|---|
name | string | No | Key name (max 64 chars, default: "Default Key") |
curl -X POST -H "X-API-Key: YOUR_KEY" \
-H "Content-Type: application/json" \
-d '{"name": "Production App"}' \
"https://weatherlens.dev/api/v1/keys"
// 201 Created
{
"key": "wl_live_a1b2c3d4e5f6...",
"name": "Production App",
"prefix": "wl_live_a1b2",
"plan": "starter",
"note": "Store this key securely — it cannot be retrieved again."
}curl -H "X-API-Key: YOUR_KEY" "https://weatherlens.dev/api/v1/keys"
{
"keys": [
{
"id": 42,
"prefix": "wl_live_a1b2",
"name": "Production App",
"plan": "starter",
"active": true,
"createdAt": "2025-01-10T14:30:00Z",
"lastUsedAt": "2025-01-15T08:12:00Z",
"requestsToday": 127
}
]
}| Param | Type | Required | Description |
|---|---|---|---|
id | integer | Yes | Key ID (from GET /keys) |
curl -X DELETE -H "X-API-Key: YOUR_KEY" \
"https://weatherlens.dev/api/v1/keys?id=42"
{ "revoked": true, "id": 42 }Get detailed usage statistics for your account, broken down by day and endpoint.
| Param | Type | Required | Description |
|---|---|---|---|
key_id | integer | No | Filter to a specific key |
days | integer | No | Lookback period (default: 30, max: 90) |
curl -H "X-API-Key: YOUR_KEY" "https://weatherlens.dev/api/v1/usage?days=7"
{
"plan": {
"name": "starter",
"requestsPerDay": 5000,
"requestsPerMinute": 60
},
"keys": [
{
"id": 42,
"prefix": "wl_live_a1b2",
"name": "Production App",
"requestsToday": 127,
"lastUsed": "2025-01-15T08:12:00Z"
}
],
"usage": {
"period": "7 days",
"totalRequests": 892,
"byDay": {
"2025-01-15": 127,
"2025-01-14": 143,
"2025-01-13": 138
},
"byEndpoint": {
"/forecast": 612,
"/climate": 180,
"/accuracy": 100
}
}
}| Code | Meaning |
|---|---|
400 | Bad request — missing or invalid parameters |
401 | Unauthorized — missing or invalid API key |
403 | Forbidden — endpoint not available on your plan |
404 | Not found — no data for the given parameters |
429 | Rate limited — daily or per-minute limit exceeded |
502 | Bad gateway — upstream data source temporarily unavailable |
All error responses include an error field:
{ "error": "lat and lon are required numeric parameters." }No SDK required — WeatherLens is a simple REST API that works with any HTTP client. Here are examples in popular languages:
const res = await fetch(
"https://weatherlens.dev/api/v1/forecast?lat=28.38&lon=-81.57",
{ headers: { "X-API-Key": process.env.WEATHERLENS_KEY } }
);
const data = await res.json();
console.log(data.forecast[0].temperature.highF); // 78import requests
resp = requests.get(
"https://weatherlens.dev/api/v1/forecast",
params={"lat": 28.38, "lon": -81.57, "days": 7},
headers={"X-API-Key": "wl_live_your_key"},
)
data = resp.json()
print(data["forecast"][0]["temperature"]["highF"]) # 78curl -s -H "X-API-Key: wl_live_your_key" \ "https://weatherlens.dev/api/v1/forecast?lat=28.38&lon=-81.57" | jq .