Fire spread
Run a fire spread simulation from any cluster or point.
/v1/fire-spread - choose between different models and ignition settings.
Attributes
| Field | Required | Default | Notes |
|---|---|---|---|
clusterId |
no | id of a feature in deepfire:clusters |
|
latitude, longitude |
no | A single-point ignition instead of a cluster | |
durationHours |
yes | 1–24 | |
model |
no | elmfire |
elmfire or forefire |
ensembleMembers |
no | 1 | 1–50 |
sources |
no | see below | source codes from Data sources |
lookbackHours |
no | 24 | 1–168; only hotspots within this timeframe seed the simulation |
domainBufferKm |
no | 25 | 5–50; km around the ignition the model may spread into, see Model parameters |
elmfire |
no | ELMFIRE overrides, only with model: elmfire, see Model parameters |
One of clusterId or latitude/longitude is required.
Examples
You can initate a fire spread either from a satellite cluster or a point.
For the cluster, you can pass in the cluster id:
curl -s -i -X POST "https://api.deepfire.co/v1/fire-spread/simulations" \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{"clusterId": "65d45ca4-a7b5-4d7e-85f3-516163c2a31d", "durationHours": 12}'
Alternatively, you can pass in a lat lon value:
curl -s -X POST "https://api.deepfire.co/v1/fire-spread/simulations" \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{"latitude": 39.0, "longitude": -105.5, "durationHours": 6}'
Choosing the ignition from a cluster
The fire is seeded from the cluster’s hotspots. sources is an include-list of exact
source codes, the same values you filter hotspots by; to leave a satellite out, don’t list
it. Omitted, it means our default set of high confidence satellite sources.
Only VIIRS and Landsat from the last six hours, ten ensemble members:
curl -s -X POST "https://api.deepfire.co/v1/fire-spread/simulations" \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"clusterId": "65d45ca4-a7b5-4d7e-85f3-516163c2a31d",
"durationHours": 12,
"ensembleMembers": 10,
"sources": ["VIIRS_SNPP_NRT", "VIIRS_NOAA20_NRT", "VIIRS_NOAA21_NRT", "LANDSAT_NRT"],
"lookbackHours": 6
}'
Model parameters
Every parameter is optional. Omitted ones take the defaults below, which are Deepfire’s
calibrated values for the 30 m fuel grid we run on and in places differ from ELMFIRE’s own
built-in defaults. ELMFIRE overrides go in an elmfire block using ELMFIRE’s own parameter names,
so you can read them up in the upstream reference; the block is rejected with model: forefire.
ForeFire runs take domainBufferKm only — its remaining script settings are solver numerics and
stay fixed.
The response echoes domainBufferKm and elmfire: while the run is QUEUED they hold what you
sent, and once the run has reported back they hold the full resolved set, every parameter with
the value the run used, so a stored result stays interpretable after these defaults change. The one
exception is seed, which is only echoed when you pinned it.
domainBufferKm applies to both models. It is the buffer around the ignition that defines the
modelled area; a fire that reaches its edge stops there and the result carries
summary.edgeReached: true. Larger domains cost proportionally more compute.
ELMFIRE
Names are ELMFIRE’s namelist keys, lower-cased; each is described in the
ELMFIRE input parameter reference under
&SIMULATOR,
&INPUTS,
&MONTE_CARLO and
&SPOTTING.
| Parameter | Default | Notes |
|---|---|---|
crown_fire_model |
2 | 1 Finney (2004), 2 Scott & Reinhardt (2001) |
foliar_moisture_content |
110 | Percent, 30–200. Lower values make crown fire initiation easier |
max_low |
8 | 1–50. Caps the fire ellipse’s length-to-width ratio |
crown_fire_spread_rate_limit |
250 | ft/min, greater than 0 and at most 5000. Caps crown fire rate of spread |
critical_canopy_cover |
0.39 | 0–1. Canopy cover fraction below which crown fire cannot start |
wind_speed_fluctuation_intensity |
0.3 | Above 0, at most 1; ensembles only (0 for single-member runs). Each member scales wind speed by 1 ± intensity/2 |
wind_direction_fluctuation_intensity |
0.06 | Above 0, at most 1; ensembles only (0 for single-member runs). Each member rotates wind direction by ± intensity/2 of a full circle |
seed |
random | 0–2147483647. Set it to make a run reproducible; omitted, every run draws a fresh seed |
Spotting (ember transport) sits in a nested spotting object. The engine samples each _min/_max
and _lo/_hi pair afresh on every weather band, so to pin a value set both ends of its range to
it. Give both ends when you change one: the API only checks ordering when both are present, and an
end that conflicts with the other’s default fails at run time with status: FAILED.
| Parameter | Default | Notes |
|---|---|---|
enable_spotting |
true | Master switch for ember spotting |
enable_surface_fire_spotting |
true | Allow surface fires to spot, not only crown fires |
spotting_distribution_type |
LOGNORMAL |
LOGNORMAL or UNIFORM: the distribution ember travel distances are drawn from |
critical_spotting_fireline_intensity |
1000 | kW/m. Surface fires below this intensity do not spot |
mean_spotting_dist_min / _max |
5 / 15 | Metres. Range of the mean ember travel distance |
normalized_spotting_dist_variance_min / _max |
250 / 600 | Range of the normalised variance of the spotting distance distribution |
spot_ws_exp_lo / _hi |
0.4 / 0.7 | 0–2. Wind speed exponent of the spotting distance; the dominant control on ember reach |
spot_flin_exp_lo / _hi |
0.2 / 0.4 | 0–2. Fireline intensity exponent of the spotting distance |
nembers_min |
1 | Embers per spotting event, lower bound |
nembers_max_lo / _hi |
1 / 1 | Range of the upper bound on embers per event |
global_surface_fire_spotting_percent_min / _max |
0 / 0.13 | Percent of burning surface-fire pixels that launch embers |
crown_fire_spotting_percent_min / _max |
0.1 / 1.2 | Percent of burning crown-fire pixels that launch embers |
pign_min / _max |
100 / 100 | Percent chance a landed ember ignites a spot fire |
A reproducible ten-member ensemble with gustier wind and shorter ember throws:
curl -s -X POST "https://api.deepfire.co/v1/fire-spread/simulations" \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"clusterId": "65d45ca4-a7b5-4d7e-85f3-516163c2a31d",
"durationHours": 12,
"ensembleMembers": 10,
"domainBufferKm": 30,
"elmfire": {
"seed": 42,
"wind_speed_fluctuation_intensity": 0.5,
"spotting": {
"spot_ws_exp_lo": 0.4,
"spot_ws_exp_hi": 0.5,
"mean_spotting_dist_min": 5,
"mean_spotting_dist_max": 10
}
}
}'
Poll until it finishes
curl -s -H "Authorization: Bearer $TOKEN" \
"https://api.deepfire.co/v1/fire-spread/simulations/2f8a…"
status moves from QUEUED to one of:
| Status | Meaning |
|---|---|
COMPLETED |
result holds the spread polygons |
NO_SPREAD |
The model ran but the fire did not grow meaningfully; no result |
FAILED |
See errorMessage — e.g. the cluster is outside the modelled regions |
While QUEUED, the response carries Retry-After; polling every 10 seconds is plenty. A run
that is still QUEUED after 60 minutes is marked FAILED (“Simulation timed out”).
A completed simulation (truncated):
{
"id": "2f8a…",
"status": "COMPLETED",
"clusterId": "65d45ca4-a7b5-4d7e-85f3-516163c2a31d",
"model": "elmfire",
"durationHours": 12,
"ensembleMembers": 1,
"sources": ["LANDSAT_NRT", "MODIS_NRT", "SENTINEL_3A", "SENTINEL_3B", "VIIRS_NOAA20_NRT", "VIIRS_NOAA21_NRT", "VIIRS_SNPP_NRT"],
"lookbackHours": 24,
"locationName": "Makedonski Brod, North Macedonia",
"ignitionPointCount": 52,
"ignition": { "type": "FeatureCollection", "features": [ … ] },
"domainBufferKm": 25,
"elmfire": {
"crown_fire_model": 2,
"foliar_moisture_content": 110.0,
"spotting": { "enable_spotting": true, "spot_ws_exp_lo": 0.4, "spot_ws_exp_hi": 0.7, "…": "every spotting parameter" }
},
"summary": {
"burnedAreaM2": 11835900,
"initialBurnedAreaM2": 4210200,
"edgeReached": false,
"windSpeedAvgMs": 1.5,
"windDirectionAvg": 178.7
},
"result": {
"type": "FeatureCollection",
"features": [
{
"type": "Feature",
"geometry": { "type": "MultiPolygon", "coordinates": [ … ] },
"properties": { "hour": 0, "elapsed_seconds": 0, "initial_burned": true }
},
{
"type": "Feature",
"geometry": { "type": "MultiPolygon", "coordinates": [ … ] },
"properties": { "hour": 1, "elapsed_seconds": 3600 }
},
{ "…": "one feature per hour" }
]
},
"links": { "self": "https://api.deepfire.co/v1/fire-spread/simulations/2f8a…" }
}
Already-burned interior
When the cluster has a perimeter — the linked incident’s official (NIFC) perimeter, or otherwise Deepfire’s satellite-derived perimeter — its interior is treated as already burned before the run, so the fire only spreads outward from the perimeter’s edge rather than re-burning the inside. In that case:
resultstarts with one extra feature athour: 0flagged"initial_burned": true. It is the pre-burned interior, not spread; the hourly features exclude it.summary.initialBurnedAreaM2is that interior’s area.summary.burnedAreaM2counts only the new spread, and a run that never grows past the perimeter finishes asNO_SPREAD.
Hotspots outside the perimeter still seed the run as usual. A cluster with no perimeter behaves
exactly as before: no hour-0 feature, no initialBurnedAreaM2.
Limits and errors
| Limit | Value |
|---|---|
| Runs in flight | 2 per API client; a third request gets 429 too-many-simulations |
| Duration | 1–24 hours |
| Ensemble members | 1–50 (ignored for forefire, which always runs one member) |
| Domain | 5–50 km buffer around the ignition |
A 422 invalid-request names the field in its message: malformed JSON, an unknown field
(Unknown field 'elmfire.spotting.spot_ws_exp_hihi', with the accepted names), a wrong type
(integers must be JSON numbers, booleans must be true/false), a value outside the ranges above,
an unknown sources code or model, an elmfire block with model: forefire, a wind
fluctuation intensity without an ensemble, or an inverted _min/_max pair. A 404 cluster-not-found means the cluster id is unknown.
Rules the engine checks itself, such as a single range end that conflicts with the default other
end, or an ignition outside the modelled regions, surface asynchronously as status: FAILED with an
errorMessage.
List previous simulations
Everything your organization has run, from the API or the web app, plus the simulations
Deepfire runs automatically on fires in your jurisdiction (auto: true). Newest first,
keyset-paginated; list items omit result.
curl -sG -H "Authorization: Bearer $TOKEN" \
"https://api.deepfire.co/v1/fire-spread/simulations" \
--data-urlencode "since=2026-09-01" \
--data-urlencode "limit=50"