Deforestation Methodology
The FM API offers two deforestation methodologies. Standard is the default; Enhanced is opt-in and incorporates a higher-sensitivity time-series change-detection layer derived from Dynamic World on top of the GLAD/TMF alert layers used by Standard. Enhanced costs more compute and runs longer, so callers must opt in deliberately.
This page describes the trade-off, how to enable each mode, and what changes in the response.
βΆTL;DR
| Standard (default) | Enhanced | |
|---|---|---|
| Sensitivity | GLAD + TMF deforestation alerts only | GLAD + TMF + higher-sensitivity time-series change detection |
| Detects | Confirmed deforestation events flagged by alert systems | Above + sub-canopy / progressive change Dynamic World picks up |
| Cost / runtime | Faster, cheaper | Slower, more expensive |
| Date precision | Year-rounded (YYYY-01-01 for deforestation_start/end) | Sub-year precision from the time-series break |
uncertainty_rrmse | 0 (the time-series RMSE is unused) | Non-zero, derived from the time-series fit |
agreement.dw | 0 | Populated |
| Recommended for | High-volume scans, cost-sensitive workflows, exploratory due diligence | EUDR-critical due diligence, audit response, anywhere false negatives are unacceptable |
Both modes share the same response shape β only the values change. Every deforestation row carries an
enhanced_deforestationflag so consumers can tell which methodology produced it.
βΆWhat changes in the response
The same JSON keys appear in both modes. The values shift:
| Field | Standard | Enhanced |
|---|---|---|
noncompliance_area (+ _perc) | GLAD βͺ TMF only | GLAD βͺ TMF βͺ time-series β typically larger |
uncertainty_rrmse | 0 | Real RMSE from the time-series fit |
agreement.dw | 0 | Populated |
agreement.glad, agreement.tmf | Populated | Populated |
annual_defor (JSON object) | Per-year split for GLAD/TMF alert years only | Per-year split includes time-series-detected events |
deforestation_start / deforestation_end | Rounded to year (driven by GLAD year) | Sub-year precision (driven by time-series tBreak). A time-series break date is held at least 90 days before monitoring_end, the period a break needs to settle. |
deforestation_alert (computed) | More likely no deforestation / non-critical | More likely non-critical / critical for the same plot |
deforestation_confidence (computed) | Lower tier on the methodology hierarchy | Higher tier when natural-forest + commodity overlap are present |
is_compliant (computed) | May read true when Enhanced would read false if Enhanced pushes area over the EUDR de minimis | Stricter β same threshold, more sensitive numerator |
overlap, forest_area, area, monitoring_*, ingestion_date, thumbnail_url | Unchanged | Unchanged |
enhanced_deforestation | false | true |
The thumbnail PNG also differs: the red "forest change" overlay is GLAD βͺ TMF in Standard and GLAD βͺ TMF βͺ time-series in Enhanced. Green (natural forest) and blue (commodity) channels are unaffected by the methodology choice.
βΆTwo things in the API are called "deforestation"
Worth stating plainly, because the names collide and the numbers are unrelated:
| Where | What it is |
|---|---|
The deforestation metric β /metrics/{type}/{id}/deforestation, and relationships.metrics.deforestation on an asset row (?include=metrics.deforestation) | The measurement this document describes: areas, agreement, alert dates, confidence. |
The EUDR compliance roll-up β attributes.deforestation on an asset row (?include=deforestation) | Counts and areas across a location's catchment: total_plots, compliant_plots, non_compliant_plots, unknown_plots, total_area_ha, compliant_area_ha. |
The roll-up is derived from per-plot verdicts, which are derived from the metric. So they move together, but they are not the same figure and neither is a substitute for the other. A dashboard that reports "deforestation" should say which one it means.
Two caveats on the roll-up's counts, both of which change numbers a customer may have recorded earlier:
- It counts the plots of current records only. A plot whose record a later upload replaced is excluded (EPO-2331). A count that fell after a re-upload usually means this, not lost data.
- It still double counts across entity generations for a small number of locations: one current record's location can own two generations of plots, and both are counted, until EPO-1899 lands the read-side lineage fix. So a roll-up total can exceed the plot count a caller counts by hand.
βΆHow to enable β request examples
enhanced_deforestation lives inside the metric_options block on POST /ingestions/assets and PUT /ingestions/assets. It is a per-metric option: it can only be set when metrics includes "deforestation". The API rejects the request with a 400 otherwise. Default is false β omit metric_options to keep Standard.
Schema rule:
metric_options.enhanced_deforestationrequiresmetricsto include'deforestation'. Sending it without that metric β or under theassessmentsblock, where it lived in earlier drafts β returns aVALIDATION_ERROR.
βΆStandard (default)
POST /ingestions/assets
Content-Type: application/json
x-api-key: <KEY>
{
"location_type": "plot",
"commodity_type": "palm",
"metrics": ["deforestation"],
"end_date": "2024-12-31",
"assessments": {
"include_core": true,
"include_hazard": true
}
}
curl equivalent:
curl -sS -X POST https://fm.epoch.blue/ingestions/assets \
-H "x-api-key: $EPOCH_API_KEY" \
-H "content-type: application/json" \
-d '{
"location_type": "plot",
"commodity_type": "palm",
"metrics": ["deforestation"],
"end_date": "2024-12-31",
"assessments": { "include_core": true, "include_hazard": true }
}'
βΆEnhanced
POST /ingestions/assets
Content-Type: application/json
x-api-key: <KEY>
{
"location_type": "plot",
"commodity_type": "palm",
"metrics": ["deforestation"],
"end_date": "2024-12-31",
"assessments": {
"include_core": true,
"include_hazard": true
},
"metric_options": {
"enhanced_deforestation": true
}
}
curl -sS -X POST https://fm.epoch.blue/ingestions/assets \
-H "x-api-key: $EPOCH_API_KEY" \
-H "content-type: application/json" \
-d '{
"location_type": "plot",
"commodity_type": "palm",
"metrics": ["deforestation"],
"end_date": "2024-12-31",
"assessments": { "include_core": true, "include_hazard": true },
"metric_options": { "enhanced_deforestation": true }
}'
βΆRe-process an existing task with the alternative methodology
PUT /ingestions/assets?filter[tags]=eq:batch-q1
Content-Type: application/json
x-api-key: <KEY>
{
"metrics": ["deforestation"],
"assessments": { "include_core": true, "include_hazard": true },
"metric_options": { "enhanced_deforestation": true }
}
curl -sS -X PUT 'https://fm.epoch.blue/ingestions/assets?filter[tags]=eq:batch-q1' \
-H "x-api-key: $EPOCH_API_KEY" \
-H "content-type: application/json" \
-d '{
"metrics": ["deforestation"],
"assessments": { "include_core": true, "include_hazard": true },
"metric_options": { "enhanced_deforestation": true }
}'
βΆValidation error β missing deforestation in metrics
deforestation in metricscurl -sS -X POST https://fm.epoch.blue/ingestions/assets \
-H "x-api-key: $EPOCH_API_KEY" \
-H "content-type: application/json" \
-d '{
"location_type": "plot",
"commodity_type": "palm",
"metrics": ["biodiversity"],
"metric_options": { "enhanced_deforestation": true }
}'
returns:
{
"errors": [
{
"code": "VALIDATION_ERROR",
"title": "metric_options.enhanced_deforestation requires `metrics` to include 'deforestation'"
}
]
}
βΆRead deforestation metrics
enhanced_deforestation appears on every deforestation response (plot, shed, facility):
curl -sS /metrics/plots/deforestation \
-H "x-api-key: $EPOCH_API_KEY"
{
"data": [
{
"id": "8a1bβ¦",
"type": "deforestation",
"attributes": {
"noncompliance_area": 0.12,
"uncertainty_rrmse": 0,
"deforestation_alert": "non-critical",
"deforestation_confidence": "low",
"is_compliant": true,
"enhanced_deforestation": false
}
}
]
}
Filter for one methodology only:
# Only Enhanced rows
curl -sS '/metrics/plots/deforestation?filter[enhanced_deforestation]=eq:true' \
-H "x-api-key: $EPOCH_API_KEY"
# Only Standard rows
curl -sS '/metrics/plots/deforestation?filter[enhanced_deforestation]=eq:false' \
-H "x-api-key: $EPOCH_API_KEY"
The same filter works on shed and facility roll-ups:
curl -sS '/metrics/facilities/deforestation?filter[enhanced_deforestation]=eq:true' \
-H "x-api-key: $EPOCH_API_KEY"
βΆHow to tell which methodology produced a row
Every plot, shed, and facility deforestation response carries enhanced_deforestation: boolean. The flag is filterable (?filter[enhanced_deforestation]=eq:true|false) on every list endpoint.
Aggregate rows (shed, facility) inherit the value from their constituent plots: true if any underlying plot was processed with Enhanced. Within a single ingestion task, all plots share one methodology, so an aggregate is uniform. Across multiple tasks, callers should filter by enhanced_deforestation before aggregating to avoid mixing methodologies.
βΆWhen to use which
Standard is the right default for:
- High-volume initial scans where you only need to flag known deforestation events.
- Cost-sensitive recurring monitoring on stable supply bases.
- Exploratory due diligence before committing to an EUDR submission.
Enhanced is the right call for:
- EUDR-critical due diligence (DDS submission, audit response).
- Any workflow where false negatives β missing real deforestation β would be unacceptable.
- Plots in regions where sub-canopy / progressive deforestation is common and GLAD/TMF alone tend to under-call.
You can re-process an existing task with the alternative methodology via PUT /ingestions/assets (see above). Existing rows keep their original methodology β enhanced_deforestation does not change retroactively.
βΆWorked example β same plot, both modes
A 12 ha cocoa plot in CΓ΄te d'Ivoire, monitored against the EUDR cut-off (monitoring_start = 2020-12-31, end_date = 2024-12-31):
| Field | Standard | Enhanced |
|---|---|---|
noncompliance_area (ha) | 0.18 | 0.61 |
noncompliance_area_perc | 0.015 | 0.051 |
uncertainty_rrmse | 0 | 0.32 |
agreement | { "glad": 0.18, "tmf": 0.10, "dw": 0 } | { "glad": 0.18, "tmf": 0.10, "dw": 0.55 } |
annual_defor | { "defor_ha_2022": 0.18 } | { "defor_ha_2022": 0.18, "defor_ha_2023": 0.43 } |
deforestation_start | 2022-01-01 | 2022-04-17 |
deforestation_end | 2022-12-31 | 2023-08-29 |
deforestation_alert | non-critical | critical |
deforestation_confidence | low | high |
is_compliant | true (under 0.5 ha de minimis) | false (over 0.5 ha) |
enhanced_deforestation | false | true |
Enhanced surfaces an additional 0.43 ha of progressive change in 2023 that GLAD and TMF didn't flag. That pushes noncompliance_area over the EUDR 0.5 ha de minimis, which flips is_compliant and lifts both deforestation_alert and deforestation_confidence.
Note:
is_compliantistrue/falseonly when the row'smonitoring_startfalls within Β±14 days of the EUDR cut-off (2020-12-31). Outside that window it isnullβ uploads with an explicit userstart_datefar from the cut-off produce a second, user-period row whoseis_compliantis undefined. See Metric Methodology β Howis_compliantis computed for the full rules.
βΆTrade-offs and limitations
- Enhanced is slower and more compute-intensive. Expect longer task durations and higher processing cost. Reserve for plots that warrant the extra sensitivity.
- Don't mix methodologies in a single aggregation. When comparing or aggregating across tasks, filter by
enhanced_deforestationfirst. The shed and facility roll-ups within one task are already uniform. - Backfilled historical rows are flagged
enhanced_deforestation = false. Data ingested before this feature shipped was processed with Standard. If you need Enhanced values for historical data, re-ingest the task withenhanced_deforestation: true. uncertainty_rrmse = 0is informational, not "perfect confidence". Standard simply doesn't compute the time-series RMSE β it's not that the prediction is certain.- The toggle only affects deforestation metrics. Biodiversity, emissions, water and other metrics are unaffected.