Endpoint reference for the Biodiversity Dynamics Simulation (BDS) module + related v3 endpoints used by the Explore page.
2 (Pasoh, location_id=1) or 50 (the other plot, location_id=2).
The BDS module has two harvest-calculation modes. Pick the one you're building:
Auto Calculate Tree Selection — Heavy / Medium / Light regimes computed for you in one call, each with residual stand, logging damage, and a 30-year projection.
Trend → BDS → Manual — the page-by-page flow where the user hand-picks trees from a map/list, then saves & compares selections as projects.
This page documents the shared setup endpoints that both modes (and the Explore page) depend on.
/v3/bds/compartments — list valid compartment sizes (dropdown)/v3/bds/years — valid census years per compartment/v3/bds/simulation — Pre-Felling + Candidate Trees (BDS Page 1)/v3/species-options — Scientific Name dropdown, scoped to compartment + year/v3/filter-options — faceted filter values (only show options that have data)/v3/flora — paginated per-tree records (Explore page / Manual map + list source)/v3/bds/auto-selection — on the Auto page/v3/bds/manual-selection + /v3/bds/projects* — on the Manual pageStatic list of valid compartment sizes for the Hectare dropdown.
None.
curl "https://api.wildvine.kotaksakti.com/v3/bds/compartments"
{
"data": [
{ "compartment_hectare": 2, "location_id": 1 },
{ "compartment_hectare": 50, "location_id": 2 }
]
}
Available census years for a given compartment. Use this to populate the Year dropdown so it never offers a year with no data.
| Name | Type | Required | Description |
|---|---|---|---|
compartment_hectare | integer | required | 2 or 50 |
curl "https://api.wildvine.kotaksakti.com/v3/bds/years?compartment_hectare=50"
{
"data": [1986, 1990, 1995, 2000, 2005, 2011],
"compartment_hectare": 50
}
{ "detail": "compartment_hectare=99 is not valid. Valid options: [2, 50]" }
Full data for BDS Page 1 (Pre-Felling): tree-density metrics with comparison percentages, distribution charts, and Candidate Trees summary + per-species breakdown. This is the shared entry screen before the user branches into Auto or Manual.
| Name | Type | Required | Description |
|---|---|---|---|
year | integer | required | Census year, e.g. 2021 |
compartment_hectare | integer | required | 2 or 50 |
curl "https://api.wildvine.kotaksakti.com/v3/bds/simulation?year=2021&compartment_hectare=50"
{
"pre_felling": {
"tree_density": { "value": integer, "change_pct": integer },
"tree_density_per_ha": { "value": float, "change_pct": integer },
"volume_m3_per_ha": { "value": float, "change_pct": integer },
"basal_area_m2_per_ha": { "value": float, "change_pct": integer },
"total_biomass_t": { "value": float, "change_pct": integer },
"total_carbon_t": { "value": float, "change_pct": integer },
"dipterocarp_density_per_ha": { "value": float, "change_pct": integer }
},
"distributions": {
"species_group_density": [
{ "group": "Non-dipterocarp", "value": integer }
],
"dbh_size_class_density": [
{ "class": "30-45cm" | "45-60cm" | "60-75cm" | "75-90cm" | ">90cm", "value": integer }
]
},
"candidate_trees": {
"summary": {
"tree_density": integer,
"tree_density_per_ha": float,
"volume_m3": float,
"basal_area_m2": float,
"total_biomass_t": float,
"total_carbon_t": float,
"price_rm": float
},
"species_breakdown": [
{
"species_group": "Dipterocarp" | "Non-dipterocarp" | "Chengal",
"cutting_limit_cm": float,
"tree_density": integer,
"tree_density_per_ha": float,
"volume_m3": float,
"volume_m3_per_ha": float,
"basal_area_m2": float,
"basal_area_m2_per_ha": float,
"total_biomass_t": float,
"total_biomass_t_per_ha": float,
"total_carbon_t": float,
"total_carbon_t_per_ha": float
}
]
},
"meta": {
"compartment_hectare": integer,
"year": integer,
"updated_at": "2026-06-04T08:00:00Z"
}
}
{
"pre_felling": {
"tree_density": { "value": 3750, "change_pct": 91 },
"tree_density_per_ha": { "value": 75.0, "change_pct": 91 },
"volume_m3_per_ha": { "value": 138.52, "change_pct": 86 },
"basal_area_m2_per_ha": { "value": 15.26, "change_pct": 49 },
"total_biomass_t": { "value": 267.46, "change_pct": 63 },
"total_carbon_t": { "value": 125.71, "change_pct": 63 },
"dipterocarp_density_per_ha": { "value": 21.1, "change_pct": 28 }
},
"distributions": {
"species_group_density": [
{ "group": "Non-dipterocarp", "value": 2631 },
{ "group": "Dipterocarp", "value": 983 },
{ "group": "Chengal", "value": 72 },
{ "group": "Pioneer", "value": 64 }
],
"dbh_size_class_density": [
{ "class": "30-45cm", "value": 2307 },
{ "class": "45-60cm", "value": 794 },
{ "class": "60-75cm", "value": 320 },
{ "class": "75-90cm", "value": 167 },
{ "class": ">90cm", "value": 162 }
]
},
"candidate_trees": {
"summary": {
"tree_density": 700, "tree_density_per_ha": 14.0,
"volume_m3": 4255.64, "basal_area_m2": 366.22,
"total_biomass_t": 6323.56, "total_carbon_t": 2972.07,
"price_rm": 365386.78
},
"species_breakdown": [
{ "species_group": "Dipterocarp", "cutting_limit_cm": 65, "tree_density": 262, "...": "..." },
{ "species_group": "Non-dipterocarp", "cutting_limit_cm": 55, "tree_density": 396, "...": "..." },
{ "species_group": "Chengal", "cutting_limit_cm": 70, "tree_density": 42, "...": "..." }
]
},
"meta": { "compartment_hectare": 50, "year": 2021, "updated_at": "2026-06-04T08:00:00Z" }
}
change_pct = percentage of the PF metric (DBH≥30cm) relative to all trees in the dataset.
E.g. tree_density.change_pct = 91 means DBH≥30 trees are 91% of all trees.
Options for the Scientific Name dropdown on the Trend / Overview pages, scoped to the selected compartment + year. Returns only species that actually have records in that selection, so the user can't pick a name that yields an empty result. Each option carries its species_group, so the FE can auto-fill the Species Group filter when a name is chosen.
species_group field on the selected option).
| Name | Type | Required | Description |
|---|---|---|---|
location_ids | integer[] | optional | 1 = 2ha plot, 2 = 50ha plot. Comma-separated or repeated. |
years | integer[] | optional | e.g. ?years=2011. Comma-separated or repeated. |
Omitting both returns every species across the whole dataset. In practice pass the compartment's location_id and the selected year to scope it.
curl "https://api.wildvine.kotaksakti.com/v3/species-options?location_ids=2&years=2011"
{
"data": [
{
"species_id": "ACTIM1",
"scientific_name": "Actinodaphne macrophylla",
"species_group": "Non-dipterocarp",
"tree_count": 4
},
{
"species_id": "CANAPA",
"scientific_name": "Canarium patentinervium",
"species_group": "Non-dipterocarp",
"tree_count": 14
}
// ... sorted alphabetically by scientific_name
],
"params": { "location_ids": "2", "years": "2011" }
}
[]. A compartment/year with no rows returns { "data": [], "params": {...} }.
species_group is the species' visual group (group_new). A few species carry values outside the 5 dropdown options (e.g. Non-commercial, Partially commercial) — decide on the FE how to map those before cascading.
Faceted filter values for the Trend / Explore filter bar — returns only the options that still have data given the current selection, so the FE can collapse each dropdown to what's actually available. Scope is location_ids + years; pass the user's current picks to narrow the rest.
| Name | Type | Required | Description |
|---|---|---|---|
location_ids | integer[] | optional | Compartment scope. 1 = 2ha, 2 = 50ha. |
years | integer[] | optional | Census year scope, e.g. 2011. |
scientific_name | string[] | optional | Current Scientific Name pick(s). |
species_ids | string[] | optional | Current species code pick(s). |
species_groups | string[] | optional | Current Species Group pick(s). All/empty = no filter. |
dbh_size_classes | string[] | optional | Current DBH Size Class pick(s). All/empty = no filter. |
protected_tree | string[] | optional | Current Protected Tree pick(s) (IUCN categories). All/empty = no filter. |
curl "https://api.wildvine.kotaksakti.com/v3/filter-options?location_ids=2&years=2011&scientific_name=Shorea%20pauciflora"
{
"data": {
"scientific_names": [
{ "species_id": "...", "scientific_name": "...", "species_group": "...", "tree_count": integer }
],
"species_groups": ["Dipterocarp"],
"dbh_size_classes": ["0_15", "15_30", "30_45", "45_60", "60_75", "75_90"],
"protected_tree": ["Least Concern (LC)"], // IUCN categories present
"protected_binary": { "has_protected": true, "has_unprotected": false }
},
"params": { "location_ids": "2", "years": "2011", "scientific_name": "Shorea pauciflora", ... }
}
dbh_size_classes come back in canonical order (0_15 … 90). protected_tree
lists the IUCN category labels present; protected_binary tells you whether protected and/or
unprotected (no category) trees exist, in case the dropdown also offers a plain protected/unprotected toggle.
With no selection, every facet returns the full set available for that compartment + year.
Paginated per-tree records for the Explore page. Also the source of points/rows for the Manual map & list. Supports filtering by year, location, species, DBH class, and protection status.
| Name | Type | Required | Description |
|---|---|---|---|
years | integer[] | optional | e.g. ?years=2017&years=2021 |
location_ids | integer[] | optional | 1 = 2ha plot, 2 = 50ha plot |
species_ids | string[] | optional | Species codes from species.csv |
species_groups | string[] | optional | Dipterocarp, Non-dipterocarp, Chengal, Pioneer |
dbh_size_classes | string[] | optional | 0_15, 15_30, 30_45, 45_60, 60_75, 75_90, 90 |
protected_tree | string[] | optional | true / false (or 1 / 0). Binary only — no IUCN categories. |
scientific_name | string[] | optional | Partial match on scientific name |
page | integer | optional | 1-based page number (default 1) |
page_size | integer | optional | Default 10, max 5000 |
curl "https://api.wildvine.kotaksakti.com/v3/flora?years=2021&location_ids=2&dbh_size_classes=30_45&protected_tree=true&page_size=20"
{
"data": [
{
"tag": string,
"species": string, // species code
"species_name": string,
"species_group": string,
"redlist": "0" | "1", // 1 = protected
"timber_group": string,
"quad": string,
"xco": float, "yco": float,
"longitude": float, "latitude": float,
"year": integer,
"data": float, // DBH in cm
"dbh_size_class": string,
"extrapolated": bool,
"basal_area": float,
"height": float,
"volume": float,
"agb": float,
"bgb": float,
"biomass": float,
"carbon_stock": float,
"price_rm": float,
"location_id": integer,
// per-hectare equivalents (value / the tree's plot area). Sum across a
// plot = the totals-row per-ha. biomass/carbon are in t/ha and tC/ha.
"area_ha": float,
"basal_area_m2_per_ha": float,
"volume_m3_per_ha": float,
"biomass_t_per_ha": float,
"carbon_tC_per_ha": float
}
],
"area_ha": float, // total area (ha) of the plots in this result
"pagination": {
"page": integer,
"page_size": integer,
"total": integer,
"total_pages": integer,
"has_next": bool,
"has_prev": bool
},
"params": {
"years": "2021",
"species_groups": null,
"location_ids": "2",
"species_ids": null,
"dbh_size_classes": "30_45",
"protected_tree": "true",
"scientific_name": null
}
}
0/1 (not IUCN categories like CR/EN/VU).
Sending true returns trees with redlist=1; false returns redlist=0.
compartment_hectare=2 → Pasoh (location_id=1); compartment_hectare=50 → other plot (location_id=2)./v3/bds/years to populate the dropdown./v3/bds/projects* persist only the selection's inputs (DynamoDB wildvine_bds_projects, per-user); the manual-selection payload is re-derived on read so saved projects never go stale. See the Manual page.UPM-Precision-Biodiversity/wildvine-apiLast updated 2026-06-09 · Hosted on Cloudflare Pages