API Reference
Astera delivers a single unified WorldState for any coordinate on Earth — weather, marine, astronomy, air quality, flood risk, and scored activity recommendations in one call.
Overview
All responses are JSON. All requests are GET. Coordinates are decimal degrees (WGS84). The API is stateless — no session or pagination.
The base URL is the same origin as this page when accessed via the dashboard. For direct API access, use the URL below.
Base URL
https://astera-api.onrender.com
All endpoints are prefixed with /api/v1/.
Authentication
Protected endpoints require an API key. Pass it in one of two ways:
| Method | Example |
|---|---|
| X-API-Key header | X-API-Key: your_key_here |
| Bearer token | Authorization: Bearer your_key_here |
Keys are provisioned by Harrow Point Software. Contact us to request access.
Rate limits
Requests are limited to 60 per minute per IP address. Exceeding this returns 429 Too Many Requests. Responses are cached for 5 minutes per location (1 km precision), so repeated calls for the same area are served instantly.
World State
Returns the full current WorldState for a coordinate: weather, marine, astronomy, air quality, flood risk, activity scores, and recommendations.
Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
| lat | float | Yes | Latitude, −90 to 90 |
| lon | float | Yes | Longitude, −180 to 180 |
Example request
curl "https://astera-api.onrender.com/api/v1/world-state?lat=51.5074&lon=-0.1278" \ -H "X-API-Key: your_key_here"
const res = await fetch(
'https://astera-api.onrender.com/api/v1/world-state?lat=51.5074&lon=-0.1278',
{ headers: { 'X-API-Key': 'your_key_here' } }
);
const data = await res.json();
import requests
r = requests.get(
'https://astera-api.onrender.com/api/v1/world-state',
params={'lat': 51.5074, 'lon': -0.1278},
headers={'X-API-Key': 'your_key_here'}
)
data = r.json()
Response schema
{
"location": {
"name": "London",
"country": "GB",
"latitude": 51.5074,
"longitude": -0.1278,
"timezone": "Europe/London"
},
"time": {
"requested_at": "2026-06-01T14:30:00Z",
"local_time": "2026-06-01T15:30:00+01:00",
"is_daylight": true
},
"weather": {
"temperature_celsius": 18.4,
"wind_speed_kph": 14.0,
"wind_gust_kph": 22.0,
"wind_direction_degrees": 240,
"precipitation_mm": 0.0,
"visibility_km": 24.1,
"humidity_pct": 62.0,
"uv_index": 4.2,
"condition": "partly_cloudy"
},
"marine": {
"tide_state": "rising",
"next_low_tide": "2026-06-01T19:42:00Z",
"next_high_tide": "2026-06-02T01:15:00Z",
"wave_height_m": 0.4,
"swell_period_sec": 8.2,
"sea_temp_c": 14.1
},
"astronomy": {
"sunrise": "2026-06-01T04:51:00Z",
"sunset": "2026-06-01T21:08:00Z",
"moon_phase": "waxing_gibbous",
"moon_illumination_pct": 72.3
},
"air_quality": {
"aqi": 38,
"category": "Good",
"pm25_ugm3": 4.2,
"pm10_ugm3": 8.1,
"no2_ugm3": 12.4,
"o3_ugm3": 67.0
},
"risk": {
"weather_warning": false,
"flood_risk": "low",
"marine_risk": "low",
"air_quality_risk": "low"
},
"activity_scores": {
"drone": 8,
"stargazing": 3,
"photography": 9,
"coastal_walk": 7,
"fishing": 6,
"sailing": 7,
"hiking": 9,
"cycling": 8,
"surfing": 3,
"running": 9,
"swimming": 4,
"birdwatching": 7,
"kayaking": 8
},
"recommendations": [
{
"type": "photography",
"score": 9,
"summary": "Partly cloudy skies add drama and texture — good conditions for landscapes."
},
{
"type": "hiking",
"score": 9,
"summary": "Excellent hiking conditions. Enjoy the trail."
}
]
}
marine is null for inland locations. air_quality may be null if the provider is temporarily unavailable. All other fields are always present.Forecast
Returns a daily 7-day forecast with aggregated weather and activity scores for each day.
Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
| lat | float | Yes | Latitude, −90 to 90 |
| lon | float | Yes | Longitude, −180 to 180 |
| days | int | No | Number of days, 1–9. Defaults to 7. |
Example request
curl "https://astera-api.onrender.com/api/v1/forecast?lat=51.5074&lon=-0.1278&days=7" \ -H "X-API-Key: your_key_here"
const res = await fetch(
'https://astera-api.onrender.com/api/v1/forecast?lat=51.5074&lon=-0.1278&days=7',
{ headers: { 'X-API-Key': 'your_key_here' } }
);
const { location, forecast } = await res.json();
import requests
r = requests.get(
'https://astera-api.onrender.com/api/v1/forecast',
params={'lat': 51.5074, 'lon': -0.1278, 'days': 7},
headers={'X-API-Key': 'your_key_here'}
)
data = r.json()
Response schema
{
"location": { ... },
"forecast": [
{
"date": "2026-06-01",
"weather": {
"temperature_high_celsius": 21.3,
"temperature_low_celsius": 12.8,
"wind_speed_kph": 18.0,
"wind_direction_degrees": 230,
"precipitation_mm": 0.0,
"visibility_km": 22.5,
"condition": "partly_cloudy"
},
"astronomy": {
"sunrise": "2026-06-01T04:51:00Z",
"sunset": "2026-06-01T21:08:00Z",
"moon_phase": "waxing_gibbous",
"moon_illumination_pct": 72.3
},
"activity_scores": { ... },
"best_activity": "hiking"
}
]
}
Alerts
Register a webhook to be called automatically when an activity score meets your threshold. The poller checks all active rules every 15 minutes. A per-rule cooldown (default 60 minutes) prevents repeated firings.
Create an alert
Request body
| Field | Type | Required | Description |
|---|---|---|---|
| lat | float | Yes | Latitude of the location to watch |
| lon | float | Yes | Longitude of the location to watch |
| activity | string | Yes | Activity key, e.g. drone |
| threshold | int | Yes | Minimum score (1–10) to trigger the alert |
| webhook_url | string | Yes | https URL to POST to when the alert fires |
| label | string | No | Human-friendly name for this rule |
| cooldown_minutes | int | No | Minimum gap between firings. Defaults to 60. |
curl -X POST "https://astera-api.onrender.com/api/v1/alerts" \
-H "X-API-Key: your_key_here" \
-H "Content-Type: application/json" \
-d '{
"lat": 51.5074,
"lon": -0.1278,
"activity": "drone",
"threshold": 7,
"webhook_url": "https://your-server.example.com/hooks/astera",
"label": "London drone alert",
"cooldown_minutes": 120
}'
const res = await fetch('https://astera-api.onrender.com/api/v1/alerts', {
method: 'POST',
headers: {
'X-API-Key': 'your_key_here',
'Content-Type': 'application/json',
},
body: JSON.stringify({
lat: 51.5074, lon: -0.1278,
activity: 'drone', threshold: 7,
webhook_url: 'https://your-server.example.com/hooks/astera',
label: 'London drone alert',
cooldown_minutes: 120,
}),
});
const alert = await res.json(); // contains the generated id
Webhook payload
When an alert fires, Astera sends a POST to your webhook_url with this body:
{
"alert_id": "a3f8c1d2b4e5f609",
"label": "London drone alert",
"activity": "drone",
"score": 8,
"threshold": 7,
"fired_at": "2026-06-01T07:15:00Z",
"world_state": { ... }
}
List alerts
Returns all registered alert rules.
Delete an alert
Removes the alert rule with the given id. Returns 204 No Content on success.
Test an alert
Fetches the current world state for the rule's location and immediately fires the webhook — regardless of the current score or cooldown. Useful for verifying your endpoint is reachable before relying on the poller. Returns the activity, live score, and fired timestamp.
Health check
Returns 200 OK with body pong. No authentication required. Useful for uptime monitoring and cold-start warm-up.
Activity scores
Every activity is scored 0–10 based on live conditions. Scores ≥ 5 appear in recommendations with a human-readable summary. All 13 scores are always present in the response, even for inland locations (marine-dependent activities score 0 when no coastal data is available).
Score interpretation
| Score | Meaning |
|---|---|
| 8 – 10 | Excellent conditions |
| 6 – 7 | Good conditions |
| 4 – 5 | Fair — worth considering |
| 1 – 3 | Poor — notable limiting factors |
| 0 | Not viable (storm, no data, extreme conditions) |
Weather conditions
The condition field uses a normalised string from the following set:
clear_sky · mainly_clear · partly_cloudy · overcast fog · drizzle · rain · rain_showers · snow thunderstorm · thunderstorm_with_hail · unknown
Risk levels
The risk object summarises hazard levels derived from live data.
| Field | Values | Source |
|---|---|---|
| weather_warning | true / false | Wind > 60 km/h or thunderstorm |
| flood_risk | low · moderate · high · severe | Environment Agency (England & Wales); precipitation elsewhere |
| marine_risk | low · moderate · high | Wave height thresholds |
| air_quality_risk | low · moderate · high · unknown | AQI (US EPA scale) |
Data sources
| Domain | Provider | Coverage |
|---|---|---|
| Weather | Norwegian Meteorological Institute (met.no) | Global |
| Marine / waves | Open-Meteo Marine | Global coastal |
| Tides | WorldTides → NOAA CO-OPS → Environment Agency (cascade) | Global / US / England & Wales |
| Astronomy | Computed (Meeus algorithms) | Global |
| Location | Nominatim / OpenStreetMap | Global |
| Air quality | WAQI | Global (major cities) |
| Flood risk | Environment Agency | England & Wales |