Skip to content

Research API /api/v1

Read access to the situation platform for theses, research and agency scripts: active-fire detections (NASA FIRMS/GWIS), burnt areas (EFFIS), fire danger (FWI) and the ground sensor network as raw series.

Access and keys

Keys are issued by the operator (samoLabs): request one with your name, institution and purpose via info@samolabs.de. Research keys are free of charge and time-limited; each key is for one person or one system.

Every data request carries the key as a bearer token in the Authorization header:

Authorization: Bearer ffw_YOUR_KEY

401 means: no or unknown key. Obtain access. 403 means: key known but revoked or expired. Contact the operator. An empty result with HTTP 200, by contrast, means: looked, nothing there.

The limit is 120 requests per minute per key. On 429, honour the Retry-After header.

Endpoints

Five data endpoints, all key-protected, all in GeoJSON and CSV:

GET /api/v1/hotspots
Active-fire detections with the full raw source columns (brightness temperatures, pixel size, FRP, product id). Detections are pixels, not fire counts.
GET /api/v1/burnt-areas
Burnt-area perimeters from EFFIS with all attributes. Geometry in the GeoJSON variant; the CSV variant is the attribute table.
GET /api/v1/fire-danger
Fire danger as a time series with all sub-indices of the Canadian FWI system (FFMC, DMC, DC, ISI, BUI). Exactly one model per response; never mix the reference levels country and adminArea.
GET /api/v1/sensor-stations
Station registry of the ground sensor network: the master data for the measurement series, including the simulated flag.
GET /api/v1/sensor-readings
Sensor network series as untouchable raw values in a 10-minute cycle; ?series=corrected returns the (later versioned) correction layer.

The complete machine-readable contract is available as an OpenAPI 3.0 document at GET /api/v1/docs and loads directly into Swagger UI or Postman.

Formats and time windows

Every endpoint returns GeoJSON (RFC 7946, with an additional meta block) and, with ?format=csv, a CSV variant: comma-separated, one header row, UTF-8. Both pandas.read_csv and readr::read_csv read it without extra options.

The time window comes from ?from and ?to (ISO 8601; a bare date counts as UTC midnight). For reproducible extracts always pass both bounds. The window actually used is echoed in meta.window. If meta.truncated reports a cut, narrow the window; there is deliberately no offset parameter.

Every JSON response carries meta.observation: whether the feeding data chain ran at all and how old its last success is. An empty collection means observed, nothing found; HTTP 503 means did not look. Never equate the two.

Reproducibility: the v1 commitments

The /v1 path segment is a stability commitment to ongoing theses: within v1, fields, parameters, enum values and error codes are never removed, renamed or reinterpreted. Extensions are strictly additive. A break would mean /v2, with a documented transition period for v1.

All timestamps are ISO 8601 in UTC. Research data never switches to a display time zone. The local time of the UI is presentation only.

The sensor network contains simulated demo stations. Every station and every reading therefore carries the simulated field; analyses filter it as the first step. Simulated series appear in no citable dataset.

?series=raw returns the untouchable raw series. ?series=corrected is the correction layer: it currently returns the same raw values, but with correctionModel: null, no correction applied, as a citable statement. Once server-side versioned correction models (humidity bias, co-location factors) are retrofitted, correctionModel carries the model id without any change to the response shape.

Examples

The examples are deliberately untranslated; replace HOST with the address of the installation.

Fetch with curl

curl -H "Authorization: Bearer ffw_YOUR_KEY" \
  "https://HOST/api/v1/hotspots?from=2026-07-01&to=2026-08-01&country=BA&format=csv" \
  -o hotspots_ba_2026-07.csv

Python (pandas)

import io
import requests
import pandas as pd

resp = requests.get(
    "https://HOST/api/v1/sensor-readings",
    params={"from": "2026-06-01", "to": "2026-07-01",
            "series": "raw", "format": "csv"},
    headers={"Authorization": "Bearer ffw_YOUR_KEY"},
    timeout=60,
)
resp.raise_for_status()

df = pd.read_csv(io.StringIO(resp.text), parse_dates=["measuredAtUtc"])
df = df[~df["simulated"]]  # always drop simulated demo stations

R (httr2 + readr)

library(httr2)
library(readr)

resp <- request("https://HOST/api/v1/fire-danger") |>
  req_url_query(model = "effis", from = "2026-06-01",
                to = "2026-08-01", format = "csv") |>
  req_auth_bearer_token("ffw_YOUR_KEY") |>
  req_perform()

danger <- read_csv(resp_body_string(resp))
danger <- subset(danger, level == "adminArea")  # never mix reference levels