Exports one or more variables from a station as CSV, one page at a time. There’s no window limit. This endpoint needs a Raindrop API key or a CSSL account on the Commercial plan; lower plans get 403. See Authentication.
Request
startdatetimequeryrequiredStart of the range, inclusive.
enddatetimequeryrequiredEnd of the range, exclusive. Must be after start.
pageSizeintegerquerydefault 200000Rows per page. The maximum is 200,000.
cursorstringqueryThe X-Next-Cursor value from the previous page.
stationIdstringbodyrequiredStation ID.
requestsobject[]bodyThe series to export. Each entry takes the same fields as the time series body (name, intervalType, intervalMinutes, calculated) plus optional filters: lowerValueBound, upperValueBound and qualityRange. Every entry must use the same filters. If you leave requests out, every series at the station is exported.
curl -s --compressed -X POST \
"https://raindrop.cssl.ca/api/v1/historical/bulk?start=2026-01-01T00:00:00Z&end=2026-02-01T00:00:00Z" \
-H "Authorization: Bearer $RAINDROP_API_KEY" \
-H "Content-Type: application/json" \
-D headers.txt -o page1.csv \
-d '{
"stationId": "12efaad4-2ddd-42c1-bba2-0c00031e4a98",
"requests": [{ "name": "airTemperature" }, { "name": "dewPointTemperature" }]
}'
Response
The body is CSV with this header row:
lat,lon,observation_name,interval_type,interval_minutes,timestamp,value,quality_base,quality_reason,group_bucket_name
lat and lon are the station’s coordinates. timestamp is ISO 8601 UTC. The quality columns hold the quality flag codes. Rows are ordered by time, then by series. The response headers tell you what came back:
| Header | Meaning |
|---|---|
X-Has-More |
True if there are more pages |
X-Next-Cursor |
Pass this as cursor to get the next page |
X-Series-Found |
False if the station has no such series |
X-Station-Id |
The station ID, when a series was found |
X-Name |
The exported variable names, when a series was found |
An empty result is still a 200 with just the header row. Check X-Series-Found: False means the series doesn’t exist, while True means it exists but has no data in the range.
Paging
Keep requesting with the returned cursor until X-Has-More is False. Leave the query and body unchanged between pages; the cursor only makes sense for the request that produced it.