Raindrop collects surface observations from weather station networks across Canada and the United States, along with ECCC weather alerts. It serves them over a JSON REST API.
https://raindrop.cssl.ca/api/v1
The OpenAPI document is at /openapi/v1.json, and there’s an interactive explorer at /swagger.
Endpoints
| Endpoint | Description | Access |
|---|---|---|
GET /stations/map/markers |
Location of every station, as GeoJSON | Public |
GET /stations/map/details |
Metadata for every station | Public |
GET /stations/{stationId} |
Metadata for one station | Public |
GET /stations/readings |
Readings for stations in an area | Public |
POST /stations/readings |
Readings for specific stations | Public |
POST /observations/series |
One variable at one station over time | Public |
GET /observations/units |
The unit of each variable | Public |
GET /alerts |
ECCC weather alerts, as GeoJSON | Public |
GET /alerts/zones |
Forecast zone boundaries | Public |
POST /historical/bulk |
Paginated CSV export | Commercial |
GET /capabilities |
What your credential can access | Public |
The raster endpoints under /products appear in the OpenAPI document, but they aren’t publishing files right now. For hail size and lightning grids, use Cyclone’s MRMS sources.
Conventions
- Times are UTC, in ISO 8601. Always send a
Zor an explicit offset. - Field names are camelCase. Fields with no value are left out of the response, not returned as
null. - Enums are strings, such as
"Instantaneous"or"Good". - Station IDs are UUIDs. They stay the same between requests.
- GeoJSON coordinates are
[longitude, latitude]. So is thecoordinatesfield on station details. - Values are converted to a standard unit per variable when they’re ingested: °C, km/h, hPa and so on. Look them up with
/observations/unitsrather than assuming. - Responses are compressed with gzip or Brotli if you send
Accept-Encoding.curl --compresseddoes this. It matters: the full station list is about 12 MB uncompressed and under 1 MB compressed.
Time windows
Endpoints that take start and end limit how much history you can request. The limit depends on your plan:
| Plan | Lookback |
|---|---|
| No account, Free | 7 days |
| Pro | 30 days |
| Commercial, or any API key | Unlimited |
The lookback applies twice:
end - startcan’t be longer than the lookback.endcan’t be further back than the lookback (plus a one-hour grace period).
Without an account, then, you can request any window of up to 7 days that ends within the last 7 days. Requests that break either rule get a 400 whose message states the limit.
Rate limits
Each IP address can make 150 requests per 10 seconds across the whole API. A short burst over the limit is queued rather than refused. Past that, the API returns 429 Too Many Requests with an empty body and no Retry-After header, so back off and retry.
Browser access (CORS)
Browsers can only call the API from *.cssl.ca sites. If you’re building a web app on another domain, make the requests from your server.
Errors
| Status | Body |
|---|---|
400 |
A JSON string describing the problem, such as "start must be before end." |
401, 403 |
Empty, or {"reason": "…"} for a rejected token. See Authentication. |
404 |
Empty or a JSON string, depending on the endpoint |
429 |
Empty |
500 |
Empty, or an RFC 7807 application/problem+json object |
Most error bodies are a bare JSON string, not an object. Parse the body as JSON and check its type before reading fields from it.