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
SensitivityGLAD + TMF deforestation alerts onlyGLAD + TMF + higher-sensitivity time-series change detection
DetectsConfirmed deforestation events flagged by alert systemsAbove + sub-canopy / progressive change Dynamic World picks up
Cost / runtimeFaster, cheaperSlower, more expensive
Date precisionYear-rounded (YYYY-01-01 for deforestation_start/end)Sub-year precision from the time-series break
uncertainty_rrmse0 (the time-series RMSE is unused)Non-zero, derived from the time-series fit
agreement.dw0Populated
Recommended forHigh-volume scans, cost-sensitive workflows, exploratory due diligenceEUDR-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_deforestation flag so consumers can tell which methodology produced it.


What changes in the response

The same JSON keys appear in both modes. The values shift:

FieldStandardEnhanced
noncompliance_area (+ _perc)GLAD βˆͺ TMF onlyGLAD βˆͺ TMF βˆͺ time-series β€” typically larger
uncertainty_rrmse0Real RMSE from the time-series fit
agreement.dw0Populated
agreement.glad, agreement.tmfPopulatedPopulated
annual_defor (JSON object)Per-year split for GLAD/TMF alert years onlyPer-year split includes time-series-detected events
deforestation_start / deforestation_endRounded 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-criticalMore likely non-critical / critical for the same plot
deforestation_confidence (computed)Lower tier on the methodology hierarchyHigher 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 minimisStricter β€” same threshold, more sensitive numerator
overlap, forest_area, area, monitoring_*, ingestion_date, thumbnail_urlUnchangedUnchanged
enhanced_deforestationfalsetrue

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:

WhereWhat 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_deforestation requires metrics to include 'deforestation'. Sending it without that metric β€” or under the assessments block, where it lived in earlier drafts β€” returns a VALIDATION_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

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": ["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):

FieldStandardEnhanced
noncompliance_area (ha)0.180.61
noncompliance_area_perc0.0150.051
uncertainty_rrmse00.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_start2022-01-012022-04-17
deforestation_end2022-12-312023-08-29
deforestation_alertnon-criticalcritical
deforestation_confidencelowhigh
is_complianttrue (under 0.5 ha de minimis)false (over 0.5 ha)
enhanced_deforestationfalsetrue

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_compliant is true/false only when the row's monitoring_start falls within Β±14 days of the EUDR cut-off (2020-12-31). Outside that window it is null β€” uploads with an explicit user start_date far from the cut-off produce a second, user-period row whose is_compliant is undefined. See Metric Methodology β€” How is_compliant is 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_deforestation first. 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 with enhanced_deforestation: true.
  • uncertainty_rrmse = 0 is 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.