API Documentation

Everything you need to integrate WeatherLens into your app.

Authentication

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.

Rate Limits

PlanDailyPer MinuteForecast DaysMonthlyAnnual
Free100107$0$0
Starter5,0006016$9/mo$90/yr
Pro50,00030016$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.

Base URL

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.

Endpoints

MethodEndpointDescriptionPlan
GET/forecastWeather forecasts up to 16 daysAll
GET/climateClimate normals (weighted averages)All
GET/accuracyForecast accuracy scoresAll
GET/historicalObserved historical weather (up to 365 days)Pro
GET/keysList your API keysAll
POST/keysCreate a new API keyAll
DELETE/keysRevoke an API keyAll
GET/usageUsage statisticsAll

GET /forecast

Get weather forecasts for a location. Coordinates are snapped to 4 decimal places. New locations are auto-registered.

Parameters

ParamTypeRequiredDescription
latnumberYesLatitude (-90 to 90)
lonnumberYesLongitude (-180 to 180)
daysintegerNoForecast days (default: 16 paid / 7 free, max: 16)

Example Response

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 }
}

Data Sources

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

Get climate normals (weighted historical averages) for a location.

Parameters

ParamTypeRequiredDescription
latnumberYesLatitude
lonnumberYesLongitude
datestringNoYYYY-MM-DD (single or comma-separated range). Omit for all 366 days.

Example Response

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 /accuracy

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.

Parameters

ParamTypeRequiredDescription
latnumberYesLatitude
lonnumberYesLongitude
monthintegerNoFilter by month (1-12)
sourcestringNoFilter by source (weatherlens, nws, open_meteo)

Example Response

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 }
}

Scoring

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 /historical

Get observed historical weather data. Pro only

Parameters

ParamTypeRequiredDescription
latnumberYesLatitude
lonnumberYesLongitude
startstringYesStart date (YYYY-MM-DD)
endstringYesEnd date (YYYY-MM-DD, max 365 day span)

Example Response

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.

/keys — API Key Management

Manage your API keys programmatically. Maximum 5 keys per account.

POST /keys — Create a Key

Body FieldTypeRequiredDescription
namestringNoKey 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."
}

GET /keys — List Keys

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
    }
  ]
}

DELETE /keys — Revoke a Key

ParamTypeRequiredDescription
idintegerYesKey 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 /usage

Get detailed usage statistics for your account, broken down by day and endpoint.

Parameters

ParamTypeRequiredDescription
key_idintegerNoFilter to a specific key
daysintegerNoLookback period (default: 30, max: 90)

Example Response

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
    }
  }
}

Error Codes

CodeMeaning
400Bad request — missing or invalid parameters
401Unauthorized — missing or invalid API key
403Forbidden — endpoint not available on your plan
404Not found — no data for the given parameters
429Rate limited — daily or per-minute limit exceeded
502Bad gateway — upstream data source temporarily unavailable

All error responses include an error field:

{ "error": "lat and lon are required numeric parameters." }

Client Libraries

No SDK required — WeatherLens is a simple REST API that works with any HTTP client. Here are examples in popular languages:

JavaScript / Node.js

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); // 78

Python

import 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"])  # 78

cURL

curl -s -H "X-API-Key: wl_live_your_key" \
  "https://weatherlens.dev/api/v1/forecast?lat=28.38&lon=-81.57" | jq .