Reference
API
The same data behind the explorer, as plain JSON. Open today — send X-API-Key (or Authorization: Bearer <key>) if key enforcement is turned on for your deployment. Republish with attribution. Rate-limited to 60 requests / minute per IP.
V2: original price references
Use /api/v2/segments for published price references, including general forestry prices with incomplete specifications. A single quote is sufficient. The min and maxvalues describe the original source quotes; median is intentionally null. Currency, unit, VAT treatment and price type stay separate. Counts describe source records, not completed transactions.
Filter with q (wood name as published), species(identified species UUID), region or stage. Lists accept limit (1–100) and return an opaque meta.next_cursor to pass as cursor. Missing specifications and old or unknown source dates remain visible.
Follow a group with /api/v2/observations?segment=<segment_key>to inspect the source records supporting it. Without a segment filter, the observations endpoint serves the original evidence register. Invalid filters return 400; unavailable data returns 503, separately from a successful empty list. These endpoints do not replace V1.
V1 conventions
- Base URL:
https://timber-index.korena.eu/api/v1 - All responses are JSON; list endpoints wrap data as
{ data: [...] }. species_idis a UUID (shared with the KORENA product catalog);region_idis a text slug;product_stageis one ofstanding_tree · roadside_log · sawlog · veneer_log · pulpwood · firewood · sawn_board · slab · finished_panel.- Prices are normalized to €/m³, ex-VAT, delivered-equivalent.
- Two dates, and they mean different things.
latest_saleis a sale date a source actually stated, and isnullwhen none was stated — which is the case for most state-forest price lists.latest_observationis the day we recorded the price and is always present.days_since_latestis measured fromlatest_observation. If you republish, date the figure fromlatest_observationand do not describe it as a sale date. - Rate limit: 60 req/min/IP (Redis-backed at the edge). Over-limit returns
429with aRetry-Afterheader.
GET /api/v1/sources
List the public sources contributing to the index.
curl https://timber-index.korena.eu/api/v1/sources{
"data": [
{
"id": "ro-romsilva",
"name": "Romsilva public auctions",
"homepage_url": "https://www.rosilva.ro",
"region_id": "ro-national",
"source_type": "official_auction",
"attribution_text": "Source: Romsilva public timber auctions",
"attribution_url": "https://www.rosilva.ro",
"is_stale": false,
"expected_freshness_days": 7
}
]
}GET /api/v1/species
List active species with bundled BG / EN / DE translations and slugs (so a downstream SEO consumer can render localized pages without a second round-trip).
curl https://timber-index.korena.eu/api/v1/speciesGET /api/v1/regions
List active regions with translations, country_code and slugs.
curl https://timber-index.korena.eu/api/v1/regionsGET /api/v1/indexes/species-region
Fetch one aggregated cell (P10 / median / P90 over the last 30 days) for a (species, region, stage) tuple, with the contributing sources and their observation weights.
Query params: species (UUID, required), region (slug, required), stage (defaults to sawlog), window (30d default or latest). Returns 400 if species or region is missing; 200 with data: null and a message if the cell is below the public-index gate.
?window=latest swaps the fixed 30-day cutoff for each cell’s most-recent batch, so slow-cadence sources (annual / quarterly indices, sparse auction archives) surface instead of disappearing. The response shape is additive: data gains market_tier (bulk / value_timber / retail_listing — the dimension that makes two cells comparable or not), sale_type, and days_since_latest.
curl "https://timber-index.korena.eu/api/v1/indexes/species-region\
?species=8f2c1a30-1111-4b22-9c33-aaaaaaaaaaaa\
®ion=ro-national\
&stage=sawlog"{
"data": {
"species_id": "8f2c1a30-1111-4b22-9c33-aaaaaaaaaaaa",
"region_id": "ro-national",
"product_stage": "sawlog",
"p10": 84,
"median": 112,
"p90": 148,
"n_observations": 37,
"n_sources": 1,
"avg_confidence": 72,
"latest_sale": "2026-05-19",
"latest_observation": "2026-05-19",
"computed_at": "2026-05-21T06:00:12.000Z"
},
"sources": [
{
"source_id": "ro-romsilva",
"source_name": "Romsilva public auctions",
"attribution_text": "Source: Romsilva public timber auctions",
"attribution_url": "https://www.rosilva.ro",
"weight": 1,
"latest_sale": "2026-05-19",
"latest_observation": "2026-05-19"
}
],
"meta": {
"computed_at": "2026-05-21T06:00:12.000Z",
"license": "Republish allowed with attribution to korena.eu/timber-index",
"attribution_html": "Data: KORENA Timber Index (timber-index.korena.eu)"
}
}GET /api/v1/indexes
Batch rollup: every published (species, region, stage) cell matching the filter in one response, instead of one request per combo. This is what korena.eu’s market pages use to render a whole species/region view in a single round-trip.
Query params: exactly one of species (UUID) or region (slug) is required — 400 otherwise. Optional stage, window (30d default or latest).
curl "https://timber-index.korena.eu/api/v1/indexes?species=8f2c1a30-1111-4b22-9c33-aaaaaaaaaaaa"{
"data": [
{
"species_id": "8f2c1a30-1111-4b22-9c33-aaaaaaaaaaaa",
"region_id": "ro-national",
"product_stage": "sawlog",
"p10": 84,
"median": 112,
"p90": 148,
"n_observations": 37,
"n_sources": 1
}
],
"total": 62
}GET /api/v1/indexes/latest
The full “latest available” index — the most-recent batch per (species, region, stage) cell, with no 30-day cutoff. Each row carries days_since_latest.
Query params (all optional): species, region, stage, limit (default 500, max 1000). Degrades to { data: [] } rather than erroring if the underlying view isn’t populated yet.
curl "https://timber-index.korena.eu/api/v1/indexes/latest?region=ro-national&limit=50"GET /api/v1/prices
Raw normalized price rows (most recent first). Optional filters: species, region, stage, limit (default 200). Each row is one normalized observation, not an aggregate.
curl "https://timber-index.korena.eu/api/v1/prices?region=ro-national&limit=50"GET /api/v1/sitemap.json
Machine-readable index of every publishable (species, region, stage) cell, with n_observations, latest_sale andlatest_observation. Used to drive downstream SEO page generation — date a generated page from latest_observation, which is always present, never from latest_sale, which is null for any cell whose sources state no sale date.
curl https://timber-index.korena.eu/api/v1/sitemap.json{
"combos": [
{
"species_id": "8f2c1a30-1111-4b22-9c33-aaaaaaaaaaaa",
"region_id": "ro-national",
"product_stage": "sawlog",
"n_observations": 37,
"latest_sale": "2026-05-19",
"latest_observation": "2026-05-19"
}
],
"total": 62
}License & building on top
You may republish derived figures with attribution to korena.eu/timber-index and a link back. Where a source carries its own attribution requirement, the per-cell sources[] block tells you the exact text.
Building something on top of the index? We’d love to hear about it. There’s no support email yet — open an issue on GitLab and we’ll respond there.