Skip to main content

Overview

You send a plot geometry, the deforestation analysis runs automatically, and you read the result as JSON and download the plot report as PDF. No article or supplier is needed — a plot with a commodity group is enough.

Permissions

Key mechanism, base URL and the general status codes are in the Introduction; how to create a key is under Settings → API Keys. Plots exist in the EUDR module only. plots:write covers everything; plots:read is enough to read the result and download the report.
In a customer workspace, the report returns 403 with EUDR compliance module is not enabled unless the EUDR module is enabled for the user the key acts as (a personal key: its owner; a company key: the workspace’s highest-ranking active user). The result JSON has no such check.

Creating a plot

POST /api/v1/plots creates one plot and starts its analysis. All fields are in the endpoint reference; what an integration needs to know:
  • geojson is required (see Geometry).
  • commodityGroup is required unless you send supplierArticleIds: one of cattle, cocoa, coffee, oil_palm, rubber, soya, wood. The API also accepts non_relevant (listed in the error message); do not send it for a plot you want analyzed. With supplierArticleIds, the group is then derived from the articles.
  • For wood, species is required — each entry with commonName and scientificName.
  • Put your own plot reference in name (see Idempotency).
  • country (ISO 3166-1 alpha-2, e.g. BR): without it (or with a value that does not resolve to a country), the low-risk skip never applies and the plot is always analyzed.

Geometry

  • Accepted: Polygon, MultiPolygon, Point and MultiPoint — as a bare geometry or as a Feature. Coordinates in WGS84, order [longitude, latitude]; an altitude (third value) is accepted but not stored. Coordinates outside longitude ±180 / latitude ±90 are rejected; nothing is saved.
  • One request creates one plot. A FeatureCollection is rejected — send each feature as its own request. Other types (LineString, GeometryCollection, …) are rejected too.
  • When size is given, a Point or MultiPoint is only accepted up to 4 ha (20,000 ha when commodityGroup is cattle); above that the EUDR requires a polygon. Without size there is no area check.

Quality checks

Before storing, the API runs the same geometry checks as the import in the app and stores the result: Removing a hole — including one the self-intersection repair encloses — makes the excluded area part of the plot: the plot gets larger. The API never swaps latitude and longitude. The create response lists the codes above in warnings ([{ "code": … }]); rounding, dropped altitude, removed duplicate points and closed or reoriented rings are not listed. On a deduplicated answer warnings is always empty, because that request stored nothing.

Idempotency

If you send the same plot again — same name, same country, same geometry (compared after the quality checks) and same supplierArticleIds — the API creates no second plot and starts no second analysis; it answers with the stored plot and "deduplicated": true. Name and country are compared ignoring case, leading and trailing spaces, and repeated spaces. Other fields of a repeat, such as commodityGroup or size, are not applied. The response carries "updated": true when producer, production dates or species of the repeat were applied, otherwise false; the field is absent when a new plot was created. A repeat of a plot stored before these checks existed is recognised too: the geometry exactly as sent is compared as well.

Checking a geometry without creating a plot

POST /api/v1/plots/validate takes the same body as create and runs the same checks, but writes nothing — no plot, no analysis (a dry run). plots:read is enough, and commodityGroup is optional. A request that create would refuse with a code gets 200 with valid: false and that code; a body that is not JSON is a 400. valid says whether create would accept the request, apart from the points listed under “Not checked” below. For a polygon with one hole, written with 6 decimals:
geometry is the geometry create would store, measuredAreaHa its area — 3.1 ha instead of the 2.68 ha of the polygon with its hole; null for points. With valid: false, errors holds the code and message create would answer, geometry and measuredAreaHa are null, and precision is null if the request was refused before the precision was measured. The dry run gives the point area cap and an invalid size a code (plot_point_area_too_large, plot_size_invalid); create answers these without one. Not checked: whether commodityGroup is missing without supplierArticleIds (create answers plot_commodity_group_required), whether the supplierArticleIds belong to your company, and whether the same plot already exists.

Polling the status

Poll every 15 to 30 seconds while the status is pending or in_progress. The app applies no per-key rate limit to these endpoints. If the analysis is failed or skipped, you can have the plot analyzed again in the app with Re-analyze (see Manage Plots). After Re-analyze, the status keeps its previous value until the analysis starts.

Reading the result

analysis holds the last stored result. It is null when none was ever stored or after the geometry changed. While a re-analysis is running (in_progress) or after a re-analysis failed, it can still hold the previous result — compare assessedAt. The texts are English and identical to the plot report.
New riskLevel values may be added; treat a value you do not know as needing review. The evidence[].dataset names are stable (JRC GFC 2020, Hansen GFC, GFW alerts, JRC TMF AnnualChange, and JRC GFT 2020 for wood only); measurementStatus, observation and relevance are human-readable and their wording may change — do not match on them.

Risk levels

This is a geospatial risk assessment, not a standalone determination of EUDR compliance.
The legacy numeric field deforestationRiskResult is 0 low (also set for exempt), 1 high, 2 moderate, or null for no result (pending, skipped, failed including INVALID); during a re-analysis or after a failed re-analysis it can still hold the previous value. Base your evaluation on analysisStatus and analysis.

Plot report (PDF)

GET /api/v1/plots/{id}/report returns the plot report as a PDF attachment. It is English and carries the same evidence rows as analysis.evidence. The file name is plot-report-<name>.pdf, where every character other than letters, digits, _ and - becomes _ (plot-report-plot.pdf without a name).
Every call renders the report anew. Download it once, when the result exists — poll the status with GET /api/v1/plots/{id}, not with the report.

Error codes

Rejected requests create nothing. The body holds error and, in the cases below, a machine-readable code:
plot_geometry_too_many_members, plot_geometry_bbox_spread_too_wide and plot_geometry_area_too_large carry limit and actual in the same unit (parts, degrees, hectares); split into several plots. For plot_geometry_too_many_vertices, simplify the geometry. These answer without a code: 400 when the body is not JSON; 400 when a Point or MultiPoint is above the area cap for its size (see Geometry); 400 when size is not a finite number ≥ 0; 403 when a supplier article does not belong to your company.

Recipe: from GeoJSON to report

1

Create the plot

The response is 201 with the plot under created and warnings (empty here). Take created.id; on a repeat the response carries "deduplicated": true.
2

Poll until the analysis is done, then read the result

Every 15 to 30 seconds, until analysisStatus is no longer pending or in_progress; the result is then in analysis:
3

Download the report