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

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/species

GET /api/v1/regions

List active regions with translations, country_code and slugs.

curl https://timber-index.korena.eu/api/v1/regions

GET /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\
  &region=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.

Free timber price API · KORENA Timber Index