Developers · quickstart
Weather API: current conditions and forecast as JSON
How to call HELPERG’s public weather endpoints: current conditions and an hourly and daily forecast for any coordinate, as JSON, with no credential. Parameters, a recorded response, units, caching, errors, limits, and the MET Norway attribution every response carries.
Full API referenceOpenAPI 3.1 documentThe weather page these endpoints serve
Before the first request
- Who may call it
- Anyone, today, without a credential: these three routes are in the public namespace
/api/public/v1. They are rate-limited per client and per route, HELPERG offers no service-level agreement for them, and additive fields may appear at any time; a breaking change would be a new version segment, not a change to these paths. There is no paid tier and nothing to sign up for — and therefore no promise about tomorrow beyond the versioning rule. - Whose data it is
- MET Norway’s, from its Locationforecast service, under CC BY 4.0. Every response carries the attribution text the licence asks for, and
meta.attributionRecords[].requiredistrue: show it wherever you show the readings. The readings are model output for a point, published by the provider — not a station observation, not a measurement, and HELPERG does not alter the values. - Where the point goes
- Coordinates are rounded to 2 decimal places (about 1.1 km) before the provider is asked, and the point in the body is the one served. That is the provider’s own terms for anonymous use, and it means two callers inside the same square share one cached answer.
The three endpoints
GET /api/public/v1/weather/current- Current conditions at a point: the first entry of the series the provider returned, with the hour it belongs to in
observedAt.latandlonare required decimal degrees;altitudeis optional metres from −500 to 9000;unitsismetric(default) orimperial, and the measurement field names change with the unit system (temperatureCbecomestemperatureF,windSpeedMpsbecomeswindSpeedMph). Shared cache: 600 seconds. GET /api/public/v1/weather/forecast- Hours and days for the same point, from the same service.
hoursdefaults to 24 and is clamped to 48;daysdefaults to 7 and is clamped to 10 — clamped, not refused, and the provider decides the real horizon, so fewer days than you asked for is its answer, not an error.tzis the IANA zone the daily records are assembled in (default UTC): a “day” is a local calendar day in that zone, and the first and last days can be partial. Shared cache: 1800 seconds. GET /api/public/v1/weather/places- Finds a place by name —
q, at least two characters, and an optionallimit. It is an optional capability: MET Norway publishes no gazetteer, so where this deployment has no place provider configured the route answers 200 with an empty list rather than an error. Resolve a name to coordinates once and cache the result on your side; do not call it per request.
Quickstart
The coordinate in these examples is central Prague. Replace it with your own point; the response shape is the same for any coordinate.
curl
curl -sS "https://helperg.com/api/public/v1/weather/current?lat=50.0755&lon=14.4378"
curl -sS "https://helperg.com/api/public/v1/weather/forecast?lat=50.0755&lon=14.4378&hours=12&days=5&tz=Europe/Prague"JavaScript
// Node.js 18+ or any runtime with fetch. No key, no header beyond Accept.
const response = await fetch("https://helperg.com/api/public/v1/weather/forecast?lat=50.0755&lon=14.4378&days=3&tz=Europe/Prague", {
headers: { Accept: "application/json" },
});
if (!response.ok) throw new Error(`HTTP ${response.status}`); // 400, 429 or 503: see Errors below
const { data, meta } = await response.json();
for (const day of data.forecast.days) {
console.log(day.date, day.temperatureMinC, day.temperatureMaxC, day.condition.code);
}
console.log(meta.attributionRecords[0].text); // show this wherever the readings are shownPython
import json, urllib.request
url = "https://helperg.com/api/public/v1/weather/current?lat=50.0755&lon=14.4378"
with urllib.request.urlopen(urllib.request.Request(url, headers={"Accept": "application/json"})) as r:
body = json.load(r)
current = body["data"]["current"]
print(current["temperatureC"], current["condition"]["code"], current["providerModelUpdatedAt"])
print(body["meta"]["attributionRecords"][0]["text"])A recorded response
Recorded from /api/public/v1/weather/current on 17 October 2026 at 15:02 UTC and trimmed to the fields this page discusses. The values are the provider’s for that model run; yours will differ.
{
"data": {
"current": {
"location": { "latitude": 50.08, "longitude": 14.44, "altitudeMetres": 267 },
"observedAt": "2026-10-17T14:00:00.000Z",
"units": "metric",
"temperatureC": 15.3,
"humidityPercent": 77.7,
"pressureHpa": 1017.3,
"windDirectionDegrees": 2.7,
"cloudCoverPercent": 26.6,
"uvIndex": 0.5,
"condition": { "code": "FAIR", "thunder": false, "dayPart": "DAY" },
"providerModelUpdatedAt": "2026-10-17T13:17:17.000Z",
"source": { "id": "met-no", "name": "MET Norway Weather API", "url": "https://www.met.no/" },
"attribution": { "text": "Weather data from MET Norway (Norwegian Meteorological Institute)…", "required": true,
"licenseName": "CC BY 4.0", "licenseUrl": "https://creativecommons.org/licenses/by/4.0/" }
}
},
"meta": {
"requestId": "835df78a-…", "generatedAt": "2026-10-17T15:02:31.535Z",
"cached": false, "cacheAgeSeconds": 0, "stale": false, "degraded": false,
"coordinatePrecision": "2 decimal places (about 1.1 km); the point in the body is the one served",
"canonicalUnits": { "temperature": "celsius", "windSpeed": "m/s", "pressure": "hPa", "precipitation": "mm" },
"attributionRecords": [ { "sourceId": "met-no", "required": true, "licenseName": "CC BY 4.0",
"termsUrl": "https://api.met.no/doc/TermsOfService", "modifiedByHelperg": true } ]
}
}Every public response has the same two halves: data, whose shape is specific to the route, and meta, which is the same everywhere — request id, generation time, whether the answer came from HELPERG’s cache and how old it is, whether it is stale, and the attribution records. The forecast puts hours[] and days[] under data.forecast; each hour carries startsAt in UTC and each day a date in the zone you asked for.
Units, freshness and what “current” means
- Units
- Metric by default: degrees Celsius, metres per second, hectopascals, millimetres;
meta.canonicalUnitsstates them. Withunits=imperialthe values are converted and the field names say so; the body’sunitsfield names the system in use, so a reading is never shown in one unit and stored in another. - How fresh: three layers, no fixed lag
- The HTTP response carries
Cache-Control: public, max-age=600for current conditions andmax-age=1800for the forecast: a shared cache, or your own, may hold a response that long on top of everything below. Underneath, HELPERG keeps the provider’s payload for as long as the provider’s ownExpiresheader says, clamped to 5 minutes to 1 hour for current conditions and 15 minutes to 6 hours for the forecast; when that passes it asks again withIf-Modified-Since, and a304keeps the same payload withmeta.cacheAgeSecondsback at 0 — so 0 means “just confirmed with the provider”, not “just produced”. The provider’s model run isproviderModelUpdatedAt;meta.fetchedAtis when the payload was fetched or last confirmed. If the provider cannot be reached once the copy has expired, the expired copy is served withmeta.stale: true,meta.degraded: trueand its real age, for as long as that age — counted from the fetch or the last304confirmation, not from the expiry — is at most 22200 seconds (370 minutes) for current conditions and 90000 seconds (25 hours) for the forecast: the policy’s default TTL (10 minutes and 1 hour) plus its stale allowance (6 hours and 24 hours), whateverExpiresactually set. A copy older than that is not served: the route answers 503. There is no promise of a maximum lag behind the provider’s newest run: a reading can be as old as these layers add up to, and the fields above say how old. - What “current” means
observedAtis the time of the first entry of the series the provider returned when the payload was fetched — normally the hour then in progress. The payload is reused for as long as the layers above allow andobservedAtstays where it was, so with an older copy it can sit hours behind the clock: compare it withmeta.fetchedAtandmeta.cacheAgeSecondsbefore calling a reading “now”. It is never the time of a measurement, because none was taken; if your product needs observations from stations, this is not the source for it.
Errors, limits and browser access
- The error envelope
- A refused request answers with one object and a stable code; the message is for a human and is not part of the contract. A missing or out-of-range coordinate is
400 VALIDATION_FAILED.The error envelope{ "error": { "code": "VALIDATION_FAILED", "message": "…", "requestId": "…" } } - 429 and 503
- Too many requests from one client answer 429 with
Retry-Afterin seconds: wait that long, do not retry sooner. A provider outage with nothing cacheable answers 503, also withRetry-After. Treat both as “later”, never as “the coordinate is wrong”. Requests are counted per route and per client in a fixed window on each serving instance, as the reference page describes — a ceiling, not a guarantee of the same figure from every edge. - Response size
- A serialised page over 1 MB is truncated and flagged
meta.truncated: true; the forecast at its maximum horizon stays far inside that. - From a browser
- Not from a third-party web page. Responses carry
Vary: Originand grantAccess-Control-Allow-Originonly to origins this deployment is configured with — HELPERG’s own — never*. Call the endpoints from your server, or from a serverless function, and pass the readings on with the attribution. - Conditional requests
- Responses carry a weak
ETag; send it back asIf-None-Matchand an unchanged answer costs a 304 instead of a body.
What this API does not provide
- Warnings and alerts. A warning belongs to the meteorological authority that issued it; this deployment carries no authority feed and derives none from a threshold.
- Sunrise, sunset, moon. They come from a different MET Norway service that this deployment does not call.
- History. Only the current run and its horizon; past readings are not stored and cannot be requested.
- More than the provider publishes. About 48 hours of hourly and roughly nine to ten days of daily values; there is no 14-day forecast because there is none at the source.
- Radar, satellite, air quality. Not part of the service read.
- A guarantee of availability. The status of the weather domain is public at API status; that page, not this one, is the place to check before relying on a call.