Verify locked versions with the Verifier role
Teams can now sign off on locked versions. A new Verifier role grants read-only access plus one capability — marking a locked version as Verified, the highest-confidence state, recorded in the audit history with an optional note. Assign the role from Users & roles, then use Mark as verified on a locked version. See Product and material versioning. Feature flagSet a dataset on an element through the API and MCP
You can now bind an emission-factor dataset to a sourced element — material, energy, or process — in the same call that creates or updates it, instead of only reading the binding back. Senddataset: { uuid } (plus an optional
datasetAmount) to point the element at a dataset; binding one makes the
element external (dataSource: external), and sending a different dataset on
update re-points it. Use /v1/database to find a dataset to bind.These writes are available through MCP as well, alongside the rest of the
element write contract: weight, packagingWeight, recycledPercent,
dataSource, supplierPartId, cpcCode, and dataQualityIndicators. Custom
transport modes accept their backing dataset as dataset too (the older
footprint field still works but is deprecated). See Datasets
and the Material reference.Justify your data quality ratings
You can now record a free-text justification alongside your data quality ratings — why those ratings were chosen, which production years and background datasets the figures rest on, and any caveats a reviewer should know. It reads and writes through the API and MCP asdataQualityIndicators.description, on
both products and materials, and is editable in the Variable app next to the
ratings it explains. See Data quality.Set data quality indicators through MCP
Data quality indicators are now available through MCP, matching what you can already do in the Variable app. When you create or update a product or material, you can record the documentation year, the share of the footprint backed by primary data, the share backed by supplier-specific data, and the five data quality ratings (technological, temporal, geographical, completeness, and reliability). The average data quality score is still calculated for you. See Data quality.Bundle or unbundle optional benefits (D)
Bill-of-materials lines placed at optional benefits (D) can now toggle between bundled and unbundled, the same as every other stage group. Bundled (the default) imports the source’s cradle-to-gate (A1–A3) total stamped onto module D; unbundled imports the source’s own module-D value — its recycling or recovery credit — into stage D. Existing inputs are unchanged: the default stays bundled. See Life-cycle stages explained.Richer dataset reference on custom transport modes
A custom transport mode is backed by a single freight emission-factor dataset, and itsdataset reference now carries the same detail as external elements:
alongside uuid and name, read responses include the source database and
the declaredUnit (a freight unit — tonne-kilometre or tonne-mile). Built-in modes have no backing dataset
and omit it. There’s no datasetAmount — a mode’s factor is a unit quantity in
its declared unit, so it adds nothing beyond declaredUnit.The enriched reference also surfaces through the MCP get_transport_mode and
list_transport_modes tools. See the
Transport mode reference.See the dataset behind an external element
External elements — materials, energy, and processes that get their impact from a single emission-factor dataset (dataSource: external) — now tell you which
dataset that is. Read responses include dataset (the backing dataset’s uuid,
name, source database, and declaredUnit) and datasetAmount (the quantity
and unit consumed). Both are absent for modeled products. If you narrow a
response with return, list dataset / datasetAmount there too or they’re
omitted.The same fields surface through the MCP element tools (get_material,
list_materials, and the energy/process element tools). See the
Material,
Energy, and
Process references.Absolute impact contributions in the inventory tab
In the app, a product’s Inventory tab now shows each element’s absolute contribution to the model — its intensity scaled by quantity into the model’s stages — instead of a per-unit intensity, so you can see what every material, process, and transport segment actually adds to the product’s footprint. The GWP-fossil contribution shows for everyone; a missing value stays a dash and a real zero shows zero.With all impact indicators enabled, a selector above the table swaps the impact column across every EN 15804+A2 indicator the model exposes — each in its own unit — defaulting to GWP-fossil. See Environmental impact indicators. PreviewAttach transport to a model input
You can now attach a freight transport lane to a model input through the public API and MCP — modeling the transport leg of a product’s bill of materials end-to-end without dropping into the app. Send atransport block
on POST / PATCH (and the bulk input endpoint) with the lane to follow and
either the material input it carries (for) or an explicit cargo weight; send
transport: null to detach.When you set for, the leg takes its lifecycle stage and cargo weight from the
carried material, so weight is derived rather than sent. Reads echo the lane,
weight, carried material, and the derived tonne-kilometres (tkm); the leg’s
carbon footprint flows into the model total. The MCP create_model_input and
update_model_input tools gain the same field. See
Models & Inputs.Deleting an import undoes the field updates it made
Deleting a product or material import no longer just removes the items it created — it also reverts the scalar updates that import made to pre-existing items. Fields it overwrote are restored to their prior values, and blanks it filled in are cleared again. The revert is guarded: any field you (or a later import) changed after the import is left untouched, so a delete never clobbers newer edits. When some fields are skipped for that reason, the app tells you how many couldn’t be reverted. See Undoing an update.Material imports default to filling in blanks
Material imports now default to Fill missing only, so re-importing a file backfills blank fields — weights, CPC/HS codes, descriptions, notes — on materials you already have, without overwriting anything you’ve already set. A stored0 or empty value still counts as set and is kept. Product and other
import types are unchanged and still default to Create new only; you can
switch either to any mode on the upload screen. See
Import match mode.You can also see which existing products an import updated, not just the ones it
created: an import’s detail view now lists updated products under their own
Updated tab.Energy and process elements in the public API
You can now manage energy and process elements through the public API and MCP, the same way you already manage materials: list them, create and update them, upload an image, and delete them — one at a time or in bulk. New/v1/energy
and /v1/process endpoints mirror /v1/material.An energy or process element behaves like any other element; what makes it
“energy” or “process” is simply its place in the taxonomy. Creating one files it
under the matching category automatically, and you can pass a taxonomy to pick
a more specific subcategory.GET /v1/material now returns materials (and any uncategorized elements), so
energy and process elements no longer appear there — reach them through their own
endpoints. See the Energy and
Process references.Update existing materials and products on import
Material and product imports now have a match mode that decides what happens when a row matches an item you already have. Pick it on the upload screen: Create new only (the default — matched rows are skipped, today’s behavior), Overwrite existing (the imported value wins), or Fill missing only (fill blanks, keep what you’ve already set). Use it to backfill enriched source data — weights, CPC/HS codes, descriptions, notes — onto items you created earlier, without re-keying them by hand.Only the item’s own fields are updated; its relationships — supplier, assigned datasets, and bill-of-materials inputs — are left untouched in every mode. Under Fill missing only, a stored0 or empty value counts as set and is kept:
Variable treats zero as a value and only a truly missing field as missing.
Re-imports still match by SKU (or name), so they never create duplicates. See
Import match mode.Set data quality indicators on materials
Material elements now have an editable data quality panel beside the dataset passport, so you can set all five pedigree-matrix dimensions — technological, temporal, and geographical representativeness, completeness, and reliability — directly on a material, not only on the dataset it points to. The aggregate data quality rating folds in all five and updates as you edit.Public API: set temporal representativeness directly
temporalDQR is now a writable data-quality indicator on product create and
update, alongside the other pedigree-matrix ratings (technologicalDQR,
geographicalDQR, completenessDQR, reliabilityDQR). Send 1 (Good — same
reporting year), 2 (Fair — less than 5 years old), or 3 (Poor — more than
5 years old).Previously temporalDQR was read-only and inferred from documentationYear;
it’s now set directly, matching the data-quality panel in the app.
documentationYear remains a separate, writable field for reference.Public API & MCP: recycled content on products
Product and material responses now carry recycled-content percentages.recycledPercent is the value you declare (0–100) — a 0 is a declared zero,
while an undeclared value is absent — and modeledRecycledPercent is the
server-computed weight-weighted average of the contributing inputs’ recycled
content, the recycled-content counterpart to modeledWeight.Each model input also carries its own recycledPercent, inherited from the
input’s source product — the source’s modeled recycled content when available,
otherwise its declared value, or 0 when there is no source product or the source
has neither — so you can trace a model’s recycled content line by line.
modeledRecycledPercent is derived from the bill of materials, read-only
(ignored if sent on create or update), and present only once a model has
contributing inputs. The same fields flow through every MCP tool that reads a
product or material.Public API & MCP: total modeled weight on products
Product and material responses now also carrymodeledTotalWeight — the gross
modeled weight, the sum of modeledWeight and modeledPackagingWeight — in the
same Amount shape ({ quantity, unit }).It’s derived at read time from the two component weights rather than stored, so
it can’t drift from them: a missing addend contributes nothing, the unit follows
the first present addend, and the field is present whenever at least one of the
two is. Like its parts it’s read-only (ignored if sent on create or update). The
same field flows through every MCP tool that reads a product or material.Filter the product inventory by dataset status
The product inventory now has a Dataset status filter so you can narrow the list to items that already have a dataset assigned (Assigned) or still need one (Unassigned). Use it to find the products missing footprint data before a bulk update. The filter applies to assignable items (products and energy); composed (live) items count as assigned.Public API & MCP: modeled packaging weight on products
Product and material responses now also carrymodeledPackagingWeight — the
server-computed sum of a model’s A1–A3 packaging input weights — alongside the
declared packagingWeight, in the same Amount shape ({ quantity, unit }).It’s the packaging counterpart to modeledWeight: compare it against the
packagingWeight you declared to mass-balance packaging the way an EPD reviewer
would. It’s derived from the bill of materials, read-only (ignored if sent on
create or update), and present only once a model has qualifying packaging inputs.
The same field flows through every MCP tool that reads a product or material.Public API & MCP: modeled weight on products
Product and material responses now carrymodeledWeight — the server-computed
sum of a model’s A1–A3 product-group material input weights (excluding packaging
and ancillary inputs) — alongside the existing weight field, in the same
Amount shape ({ quantity, unit }).Use it to compare what a model actually adds up to against the weight you
declared: weight is the value you set, while modeledWeight is derived from
the bill of materials and is read-only (ignored if sent on create or update).
It’s present only once a model has qualifying inputs. The same field flows
through every MCP tool that reads a product or material.Auto-assign transport across a bill of materials
Variable can now fill in transport for you. Instead of hand-attaching a lane to every material in a model, use Auto-assign transport on a product — or select several products on the product list and run it in bulk. For each material, Variable reads the facility it’s made at (or its supplier’s location) and the facility your product is made at, finds an existing transport lane that connects those points within a radius you choose, and creates the transport input using the material’s own weight.The closest matching lane wins; a tie with no clear winner is left for you to resolve, and transport you’ve already set is never overwritten. When the run finishes you get a summary grouped by result — assigned, no match, ambiguous, and the rest. The default radius is 50 km, adjustable per run. PreviewPublic API & MCP: categorize model inputs
You can now read and write an input’s material group through the API and MCP. Each input carries amaterialGroup array — common values are product, packaging, and
ancillary, and custom values (for example from a PCR document) are allowed.Set it on create or update and it comes back on every read (single input and
list). This lets integrations model packaging and ancillary inputs end-to-end
instead of relying on the value Variable infers. The legacy isPackaging flag
stays consistent automatically.Public API & MCP: write a dataset’s impact indicators
You can now set a dataset’s environmental impact indicators through the API and MCP — the write counterpart to reading them.PUT /v1/dataset/{uuid}/impacts takes the same keyed shape the
read endpoints return: each EN 15804+A2 indicator code (e.g. GWP-fossil,
ODP) maps to its life-cycle stage values (A1–A5, B1–B7, C1–C4,
D). Totals like A1_A3 and totalCarbonFootprint are computed for you, and
the dataset’s footprint is recalculated on write.Indicators you omit are left unchanged, so you can fill in a dataset
incrementally. The dataset must be in draft state (newly created datasets are).Using an MCP client, this means an assistant can now build a fully populated
dataset from a source document in one flow — create the dataset, then call
set_dataset_impacts to write its indicator values.Public API & MCP: all impact indicators in responses
Products, materials, datasets, switches, and database search results can now return their full set of EN 15804+A2 impact indicators — acidification, ozone depletion, water and energy use, waste, and the rest — not just carbon. Impacts come back under a new top-levelimpacts field, keyed by indicator code (for example
GWP-fossil, ODP, AP).Opt in with the impacts query parameter: ?impacts=all for everything, or
?impacts=gwp-fossil,odp,ap to filter to a subset. Without it, responses return GWP-fossil
only, so existing integrations are unaffected. The same data flows through every MCP tool that
reads these resources.The existing footprint.CO2e field is unchanged and still works, but is now deprecated in
favor of impacts["GWP-fossil"]. See Impacts for the response shape and query
semantics.Public API & MCP: manage your locations
You can now manage your company’s locations — factories, warehouses, offices, and ports — through the API and MCP, not just in the app. List the sites you already have, add new ones, update their details, and remove the ones you no longer need. Pin a site to a point on the map so it carries real coordinates, or keep it as a plain address. You can also set up a location on behalf of a supplier you work with, not only your own company.Once a location exists, reuse it anywhere you pick a place — for example the start or end of a transport route. A location that’s still in use is protected: remove the places that reference it before you can delete it.Using an MCP client, just ask your assistant to list, create, update, or delete a location.Public API & MCP: fetch a supplier by internalId
GET /v1/supplier/{id} now resolves a supplier by its uuid, syncId, or
internalId — the same internalId the API returns on the supplier — so you
can read a supplier back by the identifier you already have. The MCP
get_supplier tool accepts all three. PATCH and DELETE continue to require
the uuid.Public API & MCP: model freight transport
Build and reuse freight routes through the API. Transport lanes (/v1/transport/lane) are ordered legs, each with a mode, an origin, and a
destination; distances auto-compute from the endpoints, and a lane reports its
carbon intensity (CO2ePerTkm) rather than an absolute total — the total
materialises once cargo weight is applied. Transport modes
(/v1/transport/mode) cover the system-curated built-ins (truck,
container-ship, train, the air-* haul bands, …) plus custom modes you
create from your own freight emission-factor datasets. Lanes support full
CRUD; built-in modes are read-only, while the custom modes you create are
fully editable.The MCP server exposes the same operations as transport-lane and
transport-mode tools, so an agent can assemble routes end to end.Public API: read and write product notes
Products now expose theirnotes field through the API and MCP. GET
responses include notes, and you can set it on POST/PATCH (or via the
create_product/update_product MCP tools) alongside description.Public API: resolve addresses into transport-leg locations
Two new endpoints turn a free-text address into a referenceable location, so you can set transport-leg origins and destinations programmatically instead of pre-seeding them in the app.GET /v1/geolocation?search=... geocodes a string
like Syracuse, NY into ranked, un-persisted candidates; POST /v1/geolocation
persists a chosen candidate (by googleMapsId) or a manual point
(name + coordinates) and returns it with a uuid. Reference that uuid — or a
candidate’s googleMapsId directly — on a transport leg.The MCP server exposes the same surface as geocode_location and
create_geolocation tools.Terrestrial eutrophication now reported in mol N eq
The EP-terrestrial (Terrestrial eutrophication) impact indicator is now reported inmol N eq, matching EN 15804+A2. It was previously labelled
mol H+ eq (the acidification unit) — a mislabelling inherited from
ecoinvent, which documents the same error in its
v3.11 known issues.
The stored values are unchanged — only the unit label was corrected.Inputs editor: enter quantities in alternative units
The input amount field now groups units by dimension and lets you enter a quantity in any unit the source product supports — e.g. enter a board as2.4 m against an m²-declared product, and Variable converts to the
declared unit using the product’s conversion factors. The source
product’s length, volume, and area conversion factors are now editable
directly from the product preview sidebar. This is the UI counterpart to
the declaredAmount API shape shipped on May 22.Location picker: pick a location without an address
Picking aLocation that has no attached GeoLocation in the
transport-leg location picker now works — previously the click was
silently dropped, blocking address-less custom locations from being used
as a segment endpoint.Public API: machine-readable taxonomy path on responses
Taxonomy references on/v1/product, /v1/material, and /v1/activity
responses now include a path field (e.g. material, energy/electricity)
alongside uuid and name. The path is a stable, machine-readable grouping key
— unlike the human-readable name — so you can reliably branch or aggregate on a
category. Purely additive; existing uuid/name readers are unaffected.File import: BOM rows in mixed units
BOM imports now accept an input quantity in any unit the source product supports, even when it differs from that product’s declared unit (e.g. listing a board as2.4 m against an m2-declared product). Variable converts the value to the
declared unit for impact calculations using the product’s conversion factors and
keeps your entered value in the API. Rows whose unit has no matching conversion
factor are skipped. See the
BOM preparation guide for details.Suppliers can have their own locations
A supplier can now own one or more named locations — a factory, warehouse, or port, each with its own address — managed from the new Locations tab on the supplier page. Mark one as the default (the first one added is set automatically), and it’s used wherever a supplier needs a single address. Supplier locations also appear anywhere you pick a place, such as the origin of a transport leg, searchable by supplier name, so you can reuse “Acme — Rotterdam warehouse” instead of re-typing the address.Public API: fetch a single model input
NewGET /v1/model/{modelId}/input/{inputId} returns one input on a given model.
Responds with 404 when the input does not belong to the model (or does not
exist for this caller). The response carries the same quantity / unit /
declaredAmount shape as the list endpoint.The MCP server exposes the new endpoint as a get_model_input tool, alongside
refreshed list_model_inputs, create_model_input, and update_model_input
descriptions that surface the alternative-unit semantics introduced last week.Owner-controlled AI features toggle
Company owners can now enable or disable AI features for their company directly from Company Settings with the new “Enable AI features” switch. Previously this required Variable support to flip the company-levelDisableAI flag.Activities anchored in your company timezone
Activity dates now honor aCompany.timezone (IANA, defaulting to
Europe/Oslo), so partial inputs like "2026" or "2026-03" resolve in the
company’s timezone instead of UTC. Period filters (YTD, MTD, specific years)
bucket from the same timezone, and each Activity exposes a new timezone
field recording the zone used on write.Public API: alternative-unit response shape on /v1/model/{id}/input
GET, POST, and PATCH responses on /v1/model/{id}/input now return the quantity
and unit you supplied, even when those units are in a different dimension than the
source product’s declared unit (e.g. sending kg for an m3-declared source product
with a weight conversion factor). A new read-only declaredAmount field carries the
canonical converted amount in the source product’s declared unit — this is what
impact calculation uses. declaredAmount is present only for cross-dimensional
inputs; same-dimension entries (e.g. l against an m3-declared product) are
unchanged. declaredAmount is ignored if supplied on POST/PATCH.Bulk delete activities from the activity list
Activities can now be deleted in bulk directly from the Activity list. Select activities on the Draft or Rejected tab and use the new Delete button in the floating bulk action bar.Admin-managed maintenance windows for self-hosted
Self-hosted operators can now schedule and run maintenance windows from Admin -> Maintenance windows instead of toggling an environment variable and redeploying. Configure a recurring window (daily, weekly, or monthly in any IANA timezone) with anHH:mm start and a duration up to seven days, or
hit Start now for a one-off window.Offline ISO-3166-1 country coverage for self-hosted
The seededGeoLocation dataset now covers the full ISO-3166-1 country and territory set (plus
Kosovo, which Google Maps treats as XK). Self-hosted instances can resolve any country offline
without a Google Maps API key. Each row ships with the same googleMapsId, lat/lng, and bounds
that Google’s Geocoding API returns, so locations created via seed match locations created via
online lookup.BOM import: supplier matching and XLSX precision fixes
BOM imports now match existing suppliers bysupplierId (internalId) alone when no
supplierName is provided, so id-only rows correctly link to suppliers already in your
account instead of falling through and creating products without a supplier link. The
supplier lookup also no longer caps at the first page, so accounts with more than 250
suppliers match reliably.XLSX imports now preserve full numeric precision (previously, cells like 0.0004
displayed as 0.000 were silently truncated to the display string), normalize date
cells to ISO strings, and drop spreadsheet error sentinels (#REF!, #N/A, #VALUE!,
etc.) instead of importing them as literal strings.Bulk location import
Users can now bulk-create or update Locations from CSV or XLSX files. The Locations page exposes an Import action that maps name, address, and type columns; re-imports merge on name within the company so existing values are preserved when a column is left blank. Addresses are geocoded in the background after import.SmartEPD integration
Companies can now connect Variable to SmartEPD v2 and push EPDs directly from the platform. Owners configure the connection in Company Settings → Integrations by providing their SmartEPD API key and selecting a workspace. On each EPD, a “Sync to SmartEPD” action lets users choose a PCC and project (creating a new project if needed) and submit the EPD to SmartEPD. A sync status badge on the EPD page shows the current state (pending, syncing, synced, failed, or out of date), and a “Check status” action polls SmartEPD for the latest review state. Once an EPD is approved or published in SmartEPD, Variable automatically locks the EPD to Verified or Published to mirror the remote lock. If the EPD is edited locally after its last successful sync, the auto-lock is skipped and the record is markedout_of_date instead.Dataset resource in the public API
The public API now supports managing datasets in your account via/v1/dataset. You can list, fetch, create,
update, upload images, and delete datasets - whether they were user-created, added from the Variable Database,
or shared by a supplier. Deleting a dataset that came from the Variable Database or a supplier removes it from
your account while leaving the original in place; user-created datasets are permanently deleted.New DATASET_READ, DATASET_CREATE, DATASET_UPDATE, and DATASET_DELETE permissions gate these routes.
The same operations are exposed as MCP tools (list_datasets, get_dataset, create_dataset, update_dataset,
delete_dataset), and dataset payloads now use dedicated Dataset, NewDataset, and EditDataset schemas in
the OpenAPI spec instead of reusing Material / NewProduct / EditProduct.dataSource is no longer part of the Dataset surface. The previously documented dataSource: "database" value
has been removed from dataset responses, and sending a dataSource field in a dataset request body has no effect- the server always treats the resource as a dataset based on the route. Clients that read or write
dataSourceon the/v1/datasetendpoints should drop the field.
ProductDataSource enum used on /v1/product and /v1/material is narrowed to "model" and "external".
The "database" value is no longer accepted on those routes - datasets now have their own endpoint.Organization assignment on user invite
Admins can now assign an organization when inviting new users. The org selector appears in the invite modal and the backend creates the membership in the same transaction as user creation.Role-based access control
A new Access Control page gives a clear overview of what each role- Owner, Admin, Contributor, and Viewer - can access across your organization. Permissions are organized into five categories:
- Products - LCAs and Declarations (All roles)
- Inventory - Materials, Energy, Transport, Process, Datasets, and Activities (All roles)
- Exchange - Elements, Suppliers, Customers, Requests, and Deliveries (Owner and Admin only)
- Reports & Plans - Analyze, Report, and Plan (Owner and Admin only)
- Account - Org, Users, Locations, Company Settings, and more (Mixed access)
Extended org access control
Organization-level access control now covers transports, datasets, parts, and EPDs in addition to products and materials.Self-service dataset copying
Users can duplicate database datasets into their own company, enabling custom modifications. PreviewSecond indicator in modelling
The modelling screen now supports a secondary impact indicator alongside GWP, allowing side-by-side comparison of environmental impacts. Sorting by the second indicator is also supported.Taxonomy enforcement and dataset alignment
Taxonomy alignment is now enforced when assigning datasets to inventory items. A mismatch indicator shows when a dataset’s taxonomy differs from the input and offers a one-click update action.PERM/PENRM calculation for classified materials
Impact calculations now include PERM (primary energy from renewable materials) and PENRM (primary energy from non-renewable materials) for material inputs classified with flow types.BCCP and BCCAP rules
The impact calculation service now applies biogenic carbon content rules (BCCP for products, BCCAP for packaging) based on functional group classification, per EN 15804+A2.Geographic filtering
Search results can now be filtered by geography, making it easier to find region-specific datasets and products.A1-A3 entry mode toggle for custom datasets
Custom datasets now support toggling between individual A1, A2, A3 stage entry and a combined A1-A3 entry mode.Decimal separator override for data imports
Data imports now support explicit decimal separator selection, resolving ambiguity with European-format CSV files.Self-hosted data package delivery
Self-hosted instances now receive emission factor data packages via mounted volumes, simplifying data updates.Versioning in Public API
The public API now supports versioning for products and materials. Create new versions, list version history, and fetch specific versions via the API. Bulk endpoints updated accordingly. PreviewvarId added to Public API
All API responses now include the varId field - a human-readable, short identifier for each entity.
Preview