weatherhack-api / replacement_api.md
Ig0tU
first commit
a9814b6
# Weatherstack-Compatible API Specification
> **Complete Drop-In Replacement for Weatherstack API**
> This specification enables developers to build a fully Weatherstack-compatible weather service.
---
## Table of Contents
1. [Overview](#overview)
2. [Authentication](#authentication)
3. [Endpoints](#endpoints)
- [Current Weather](#endpoint-current-weather)
- [Historical Weather](#endpoint-historical-weather)
- [Weather Forecast](#endpoint-weather-forecast)
- [Location Autocomplete](#endpoint-location-autocomplete)
4. [Response Objects](#response-objects)
5. [Weather Codes](#weather-codes)
6. [Error Handling](#error-handling)
7. [Implementation Guide](#implementation-guide)
---
## Overview
### Base URL
```
https://api.yourweatherservice.com
```
### Protocol
- HTTP and HTTPS supported
- HTTPS recommended for production
### Response Format
All responses are JSON with `Content-Type: application/json`
---
## Authentication
Every request requires an `access_key` parameter containing the user's API key.
```
GET /current?access_key=YOUR_API_KEY&query=New York
```
### Security Best Practices
- Validate API keys on every request
- Implement rate limiting per key
- Log all API access for monitoring
---
## Endpoints
---
### Endpoint: Current Weather
Returns real-time weather conditions for one or more locations.
**URL:** `GET /current`
#### Request Parameters
| Parameter | Required | Type | Default | Description |
|-----------|----------|------|---------|-------------|
| `access_key` | Yes | string | - | API authentication key |
| `query` | Yes | string | - | Location identifier (see Location Formats) |
| `units` | No | string | `m` | Unit system: `m` (metric), `f` (fahrenheit), `s` (scientific) |
| `language` | No | string | `en` | Response language code |
| `callback` | No | string | - | JSONP callback function name |
#### Location Formats Supported
| Format | Example | Description |
|--------|---------|-------------|
| City Name | `New York` | City name, optionally with country |
| Coordinates | `40.7128,-74.0060` | Latitude,Longitude |
| US Zip Code | `10001` | 5-digit US zip code |
| UK Postcode | `SW1A 1AA` | UK postal code |
| IP Address | `153.65.8.20` | IPv4 or IPv6 address |
| Auto IP | `fetch:ip` | Auto-detect from request IP |
| Bulk Query | `New York;London;Tokyo` | Multiple locations (semicolon-separated) |
#### Example Request
```
GET /current?access_key=abc123&query=40.7128,-74.0060&units=f
```
#### Example Response
```json
{
"request": {
"type": "LatLon",
"query": "Lat 40.71 and Lon -74.01",
"language": "en",
"unit": "f"
},
"location": {
"name": "New York",
"country": "United States of America",
"region": "New York",
"lat": "40.714",
"lon": "-74.006",
"timezone_id": "America/New_York",
"localtime": "2026-01-30 12:45",
"localtime_epoch": 1738255500,
"utc_offset": "-5.0"
},
"current": {
"observation_time": "05:45 PM",
"temperature": 42,
"weather_code": 116,
"weather_icons": [
"https://api.yourweatherservice.com/images/wsymbol_0002_sunny_intervals.png"
],
"weather_descriptions": ["Partly Cloudy"],
"wind_speed": 12,
"wind_degree": 225,
"wind_dir": "SW",
"pressure": 1018,
"precip": 0,
"humidity": 55,
"cloudcover": 25,
"feelslike": 38,
"uv_index": 3,
"visibility": 10,
"is_day": "yes",
"astro": {
"sunrise": "07:08 AM",
"sunset": "05:15 PM",
"moonrise": "10:32 AM",
"moonset": "11:45 PM",
"moon_phase": "Waxing Crescent",
"moon_illumination": 25
},
"air_quality": {
"co": "234.5",
"no2": "15.2",
"o3": "48.0",
"so2": "5.1",
"pm2_5": "8.5",
"pm10": "12.3",
"us-epa-index": "1",
"gb-defra-index": "1"
}
}
}
```
---
### Endpoint: Historical Weather
Returns historical weather data for a specific date or date range.
**URL:** `GET /historical`
#### Request Parameters
| Parameter | Required | Type | Default | Description |
|-----------|----------|------|---------|-------------|
| `access_key` | Yes | string | - | API authentication key |
| `query` | Yes | string | - | Location identifier |
| `historical_date` | Yes* | string | - | Date in `YYYY-MM-DD` format |
| `historical_date_start` | Yes* | string | - | Start date for time-series |
| `historical_date_end` | Yes* | string | - | End date for time-series |
| `hourly` | No | string | `0` | Include hourly data: `1` or `0` |
| `interval` | No | integer | `3` | Hourly interval: `1`, `3`, `6`, `12`, `24` |
| `units` | No | string | `m` | Unit system |
| `language` | No | string | `en` | Response language |
*Either `historical_date` OR both `historical_date_start` and `historical_date_end` required.
#### Example Request
```
GET /historical?access_key=abc123&query=40.7128,-74.0060&historical_date=2026-01-30&units=f
```
#### Example Response
```json
{
"request": {
"type": "LatLon",
"query": "Lat 40.71 and Lon -74.01",
"language": "en",
"unit": "f"
},
"location": {
"name": "New York",
"country": "United States of America",
"region": "New York",
"lat": "40.714",
"lon": "-74.006",
"timezone_id": "America/New_York",
"localtime": "2026-01-30 12:45",
"localtime_epoch": 1738255500,
"utc_offset": "-5.0"
},
"current": {
"observation_time": "05:45 PM",
"temperature": 42,
"weather_code": 116,
"weather_icons": ["https://api.yourweatherservice.com/images/partly_cloudy.png"],
"weather_descriptions": ["Partly Cloudy"],
"wind_speed": 12,
"wind_degree": 225,
"wind_dir": "SW",
"pressure": 1018,
"precip": 0,
"humidity": 55,
"cloudcover": 25,
"feelslike": 38,
"uv_index": 3,
"visibility": 10
},
"historical": {
"2026-01-30": {
"date": "2026-01-30",
"date_epoch": 1738209600,
"astro": {
"sunrise": "07:08 AM",
"sunset": "05:15 PM",
"moonrise": "10:32 AM",
"moonset": "11:45 PM",
"moon_phase": "Waxing Crescent",
"moon_illumination": 25
},
"mintemp": 28,
"maxtemp": 42,
"avgtemp": 35,
"totalsnow": 0,
"sunhour": 9.5,
"uv_index": 3,
"hourly": [
{
"time": "0",
"temperature": 30,
"wind_speed": 8,
"wind_degree": 180,
"wind_dir": "S",
"weather_code": 113,
"weather_icons": ["https://api.yourweatherservice.com/images/night_clear.png"],
"weather_descriptions": ["Clear"],
"precip": 0,
"humidity": 65,
"visibility": 10,
"pressure": 1020,
"cloudcover": 0,
"heatindex": 30,
"dewpoint": 18,
"windchill": 25,
"windgust": 12,
"feelslike": 25,
"chanceofrain": 0,
"chanceofremdry": 95,
"chanceofwindy": 10,
"chanceofovercast": 5,
"chanceofsunshine": 90,
"chanceoffrost": 20,
"chanceofhightemp": 0,
"chanceoffog": 5,
"chanceofsnow": 0,
"chanceofthunder": 0,
"uv_index": 0
}
]
}
}
}
```
---
### Endpoint: Weather Forecast
Returns weather forecast for up to 14 days.
**URL:** `GET /forecast`
#### Request Parameters
| Parameter | Required | Type | Default | Description |
|-----------|----------|------|---------|-------------|
| `access_key` | Yes | string | - | API authentication key |
| `query` | Yes | string | - | Location identifier |
| `forecast_days` | Yes | integer | - | Number of forecast days (1-14) |
| `hourly` | No | string | `0` | Include hourly data: `1` or `0` |
| `interval` | No | integer | `3` | Hourly interval: `1`, `3`, `6`, `12`, `24` |
| `units` | No | string | `m` | Unit system |
| `language` | No | string | `en` | Response language |
#### Example Response
The forecast endpoint returns data in the same format as historical, but under the `forecast` key instead of `historical`.
---
### Endpoint: Location Autocomplete
Returns location suggestions for search/autocomplete functionality.
**URL:** `GET /autocomplete`
#### Request Parameters
| Parameter | Required | Type | Description |
|-----------|----------|------|-------------|
| `access_key` | Yes | string | API authentication key |
| `query` | Yes | string | Partial location name to search |
#### Example Response
```json
{
"request": {
"query": "New Yo",
"type": "City"
},
"locations": [
{
"id": 2459115,
"name": "New York",
"country": "United States of America",
"region": "New York",
"lat": "40.714",
"lon": "-74.006",
"timezone_id": "America/New_York",
"utc_offset": "-5.0"
},
{
"id": 2459116,
"name": "New York Mills",
"country": "United States of America",
"region": "Minnesota",
"lat": "46.518",
"lon": "-95.376",
"timezone_id": "America/Chicago",
"utc_offset": "-6.0"
}
]
}
```
---
## Response Objects
### Request Object
| Field | Type | Description |
|-------|------|-------------|
| `type` | string | Query type: `City`, `LatLon`, `IP`, `Zipcode` |
| `query` | string | Processed query string |
| `language` | string | Language code used |
| `unit` | string | Unit system: `m`, `f`, or `s` |
### Location Object
| Field | Type | Description |
|-------|------|-------------|
| `name` | string | Location name |
| `country` | string | Country name |
| `region` | string | State/region/province |
| `lat` | string | Latitude |
| `lon` | string | Longitude |
| `timezone_id` | string | IANA timezone identifier |
| `localtime` | string | Local time: `YYYY-MM-DD HH:MM` |
| `localtime_epoch` | integer | Unix timestamp |
| `utc_offset` | string | UTC offset in hours |
### Current Object
| Field | Type | Unit (f) | Description |
|-------|------|----------|-------------|
| `observation_time` | string | - | Time of observation: `HH:MM AM/PM` |
| `temperature` | integer | °F | Current temperature |
| `weather_code` | integer | - | Weather condition code |
| `weather_icons` | array | - | Weather icon URLs |
| `weather_descriptions` | array | - | Weather descriptions |
| `wind_speed` | integer | mph | Wind speed |
| `wind_degree` | integer | ° | Wind direction in degrees |
| `wind_dir` | string | - | Compass direction: `N`, `NE`, `E`, etc. |
| `pressure` | integer | mb | Atmospheric pressure |
| `precip` | number | in | Precipitation amount |
| `humidity` | integer | % | Humidity percentage |
| `cloudcover` | integer | % | Cloud cover percentage |
| `feelslike` | integer | °F | Feels-like temperature |
| `uv_index` | integer | - | UV index (0-11+) |
| `visibility` | integer | mi | Visibility |
| `is_day` | string | - | Daytime: `yes` or `no` |
### Astro Object
| Field | Type | Description |
|-------|------|-------------|
| `sunrise` | string | Sunrise time: `HH:MM AM` |
| `sunset` | string | Sunset time: `HH:MM PM` |
| `moonrise` | string | Moonrise time: `HH:MM AM/PM` |
| `moonset` | string | Moonset time: `HH:MM AM/PM` |
| `moon_phase` | string | Moon phase name |
| `moon_illumination` | integer | Illumination percentage (0-100) |
**Moon Phases:**
- New Moon
- Waxing Crescent
- First Quarter
- Waxing Gibbous
- Full Moon
- Waning Gibbous
- Last Quarter
- Waning Crescent
### Air Quality Object
| Field | Type | Description |
|-------|------|-------------|
| `co` | string | Carbon Monoxide (μg/m³) |
| `no2` | string | Nitrogen Dioxide (μg/m³) |
| `o3` | string | Ozone (μg/m³) |
| `so2` | string | Sulphur Dioxide (μg/m³) |
| `pm2_5` | string | PM2.5 (μg/m³) |
| `pm10` | string | PM10 (μg/m³) |
| `us-epa-index` | string | US EPA Air Quality Index (1-6) |
| `gb-defra-index` | string | UK DEFRA Air Quality Index |
**US EPA Index Values:**
| Index | Meaning |
|-------|---------|
| 1 | Good |
| 2 | Moderate |
| 3 | Unhealthy for Sensitive Groups |
| 4 | Unhealthy |
| 5 | Very Unhealthy |
| 6 | Hazardous |
### Historical/Forecast Day Object
| Field | Type | Unit (f) | Description |
|-------|------|----------|-------------|
| `date` | string | - | Date: `YYYY-MM-DD` |
| `date_epoch` | integer | - | Unix timestamp |
| `astro` | object | - | Astro data (see above) |
| `mintemp` | integer | °F | Minimum temperature |
| `maxtemp` | integer | °F | Maximum temperature |
| `avgtemp` | integer | °F | Average temperature |
| `totalsnow` | number | in | Total snowfall |
| `sunhour` | number | hrs | Hours of sunshine |
| `uv_index` | integer | - | UV index |
| `hourly` | array | - | Hourly data (if requested) |
### Hourly Object
| Field | Type | Description |
|-------|------|-------------|
| `time` | string | Hour: `0`, `100`, `200`...`2300` |
| `temperature` | integer | Temperature |
| `wind_speed` | integer | Wind speed |
| `wind_degree` | integer | Wind direction degrees |
| `wind_dir` | string | Compass direction |
| `weather_code` | integer | Weather code |
| `weather_icons` | array | Icon URLs |
| `weather_descriptions` | array | Descriptions |
| `precip` | number | Precipitation |
| `humidity` | integer | Humidity % |
| `visibility` | integer | Visibility |
| `pressure` | integer | Pressure |
| `cloudcover` | integer | Cloud cover % |
| `heatindex` | integer | Heat index |
| `dewpoint` | integer | Dew point |
| `windchill` | integer | Wind chill |
| `windgust` | integer | Wind gust speed |
| `feelslike` | integer | Feels-like temp |
| `chanceofrain` | integer | Rain probability % |
| `chanceofremdry` | integer | Remain dry probability % |
| `chanceofwindy` | integer | Windy probability % |
| `chanceofovercast` | integer | Overcast probability % |
| `chanceofsunshine` | integer | Sunshine probability % |
| `chanceoffrost` | integer | Frost probability % |
| `chanceofhightemp` | integer | High temp probability % |
| `chanceoffog` | integer | Fog probability % |
| `chanceofsnow` | integer | Snow probability % |
| `chanceofthunder` | integer | Thunder probability % |
| `uv_index` | integer | UV index |
---
## Weather Codes
| Code | Condition | Icon (Day) |
|------|-----------|------------|
| 113 | Clear/Sunny | ☀️ |
| 116 | Partly Cloudy | ⛅ |
| 119 | Cloudy | ☁️ |
| 122 | Overcast | ☁️ |
| 143 | Mist | 🌫️ |
| 176 | Patchy Rain Nearby | 🌦️ |
| 179 | Patchy Snow Nearby | 🌨️ |
| 182 | Patchy Sleet Nearby | 🌨️ |
| 185 | Patchy Freezing Drizzle | 🌧️ |
| 200 | Thundery Outbreaks | ⛈️ |
| 227 | Blowing Snow | 🌬️ |
| 230 | Blizzard | ❄️ |
| 248 | Fog | 🌫️ |
| 260 | Freezing Fog | 🌫️ |
| 263 | Patchy Light Drizzle | 🌧️ |
| 266 | Light Drizzle | 🌧️ |
| 281 | Freezing Drizzle | 🌧️ |
| 284 | Heavy Freezing Drizzle | 🌧️ |
| 293 | Patchy Light Rain | 🌧️ |
| 296 | Light Rain | 🌧️ |
| 299 | Moderate Rain at Times | 🌧️ |
| 302 | Moderate Rain | 🌧️ |
| 305 | Heavy Rain at Times | 🌧️ |
| 308 | Heavy Rain | 🌧️ |
| 311 | Light Freezing Rain | 🌧️ |
| 314 | Moderate/Heavy Freezing Rain | 🌧️ |
| 317 | Light Sleet | 🌨️ |
| 320 | Moderate/Heavy Sleet | 🌨️ |
| 323 | Patchy Light Snow | 🌨️ |
| 326 | Light Snow | 🌨️ |
| 329 | Patchy Moderate Snow | 🌨️ |
| 332 | Moderate Snow | 🌨️ |
| 335 | Patchy Heavy Snow | 🌨️ |
| 338 | Heavy Snow | 🌨️ |
| 350 | Ice Pellets | 🌨️ |
| 353 | Light Rain Shower | 🌦️ |
| 356 | Moderate/Heavy Rain Shower | 🌦️ |
| 359 | Torrential Rain Shower | 🌧️ |
| 362 | Light Sleet Showers | 🌨️ |
| 365 | Moderate/Heavy Sleet Showers | 🌨️ |
| 368 | Light Snow Showers | 🌨️ |
| 371 | Moderate/Heavy Snow Showers | 🌨️ |
| 374 | Light Ice Pellet Showers | 🌨️ |
| 377 | Moderate/Heavy Ice Pellet Showers | 🌨️ |
| 386 | Patchy Light Rain with Thunder | ⛈️ |
| 389 | Moderate/Heavy Rain with Thunder | ⛈️ |
| 392 | Patchy Light Snow with Thunder | ⛈️ |
| 395 | Moderate/Heavy Snow with Thunder | ⛈️ |
---
## Error Handling
### Error Response Format
```json
{
"success": false,
"error": {
"code": 101,
"type": "unauthorized",
"info": "Invalid API access key."
}
}
```
### Error Codes
| Code | Type | Description |
|------|------|-------------|
| 101 | `unauthorized` | Invalid or missing API key |
| 104 | `usage_limit_reached` | Monthly API limit exceeded |
| 105 | `function_access_restricted` | Feature not available on plan |
| 404 | `404_not_found` | Resource not found |
| 429 | `too_many_requests` | Rate limit exceeded |
| 601 | `missing_query` | No location query provided |
| 602 | `invalid_query` | Invalid location query |
| 603 | `historical_queries_not_supported` | Historical not on plan |
| 604 | `bulk_queries_not_supported` | Bulk queries not on plan |
| 605 | `invalid_language` | Unsupported language code |
| 606 | `invalid_unit` | Invalid unit parameter |
| 607 | `invalid_interval` | Invalid interval parameter |
| 608 | `invalid_forecast_days` | Invalid forecast_days value |
| 609 | `forecast_days_not_supported` | Forecast not on plan |
| 611 | `invalid_historical_date` | Invalid date format |
| 612 | `invalid_historical_time_frame` | Invalid date range |
| 613 | `historical_time_frame_too_long` | Date range > 60 days |
| 614 | `missing_historical_date` | No date provided |
| 615 | `request_failed` | Internal server error |
---
## Implementation Guide
### Required Data Sources
| Data Type | Recommended Sources |
|-----------|---------------------|
| Current Weather | Open-Meteo, OpenWeatherMap, NWS (US) |
| Location Data | GeoNames, OpenStreetMap Nominatim |
| Time Zones | IANA tzdb, Google Time Zone API |
| Sun/Moon Data | SunCalc library, USNO API |
| Air Quality | OpenAQ, WAQI, IQAir |
| Geocoding | Google Geocoding, Mapbox, HERE |
### Unit Conversions
When `units=f` (Fahrenheit):
- Temperature: Fahrenheit
- Wind Speed: mph
- Visibility: miles
- Pressure: millibars (mb)
- Precipitation: inches
When `units=m` (Metric):
- Temperature: Celsius
- Wind Speed: km/h
- Visibility: kilometers
- Pressure: millibars (mb)
- Precipitation: millimeters
When `units=s` (Scientific):
- Temperature: Kelvin
- Wind Speed: m/s
- Visibility: kilometers
- Pressure: millibars (mb)
- Precipitation: millimeters
### Caching Strategy
| Endpoint | Recommended TTL |
|----------|-----------------|
| Current | 10-30 minutes |
| Historical | 24+ hours (immutable) |
| Forecast | 3-6 hours |
| Location | 30+ days |
### Testing Checklist
- [ ] `/current` returns all required fields
- [ ] `/historical` returns properly nested date objects
- [ ] Weather codes match the reference table
- [ ] Times formatted as `HH:MM AM/PM`
- [ ] Coordinates support both positive and negative values
- [ ] Error responses include `success`, `error.code`, `error.type`, `error.info`
- [ ] Unit conversions work correctly
- [ ] Bulk queries parse semicolon-separated locations
- [ ] CORS headers configured for browser access
- [ ] Rate limiting implemented per API key
### Sample cURL Tests
```bash
# Current weather
curl "https://api.yourservice.com/current?access_key=test&query=40.7128,-74.0060&units=f"
# Historical with astro
curl "https://api.yourservice.com/historical?access_key=test&query=40.7128,-74.0060&historical_date=2026-01-30&units=f"
# Test error handling
curl "https://api.yourservice.com/current?access_key=invalid"
```
---
## Appendix: Wind Directions
| Direction | Degrees | Range |
|-----------|---------|-------|
| N | 0° | 348.75° - 11.25° |
| NNE | 22.5° | 11.25° - 33.75° |
| NE | 45° | 33.75° - 56.25° |
| ENE | 67.5° | 56.25° - 78.75° |
| E | 90° | 78.75° - 101.25° |
| ESE | 112.5° | 101.25° - 123.75° |
| SE | 135° | 123.75° - 146.25° |
| SSE | 157.5° | 146.25° - 168.75° |
| S | 180° | 168.75° - 191.25° |
| SSW | 202.5° | 191.25° - 213.75° |
| SW | 225° | 213.75° - 236.25° |
| WSW | 247.5° | 236.25° - 258.75° |
| W | 270° | 258.75° - 281.25° |
| WNW | 292.5° | 281.25° - 303.75° |
| NW | 315° | 303.75° - 326.25° |
| NNW | 337.5° | 326.25° - 348.75° |
---
*This specification enables complete compatibility with the Weatherstack API. A developer implementing this specification can provide a drop-in replacement requiring only a URL change in the consuming application.*