Skip to Content
Migrate from v1 and v2

Migrate from v1 and v2

v1 and v2 are deprecated. They keep working unchanged until 28 April 2027, and then stop. Every response from them, errors included, carries these headers:

Deprecation: @1793145600 Sunset: Wed, 28 Apr 2027 00:00:00 GMT

Deprecation is the announcement, 28 October 2026, as a Unix timestamp; Sunset is when the version stops working.

What replaces what

v1 and v2v3
GET /company/{companyId}/emissions/summarySame path on /v3, unchanged
GET /company/{companyId}/portfoliosSame path on /v3, unchanged
GET /company/{companyId}/portfolios/{portfolioId}/emissions/summarySame path on /v3, unchanged
GET /companyGET /v3/company, reshaped
POST /company/{companyId}/data/data-point (both bodies)POST /v3/company/{companyId}/data-points, reshaped
POST /company/{companyId}/finance/posting-journal-linePOST /v3/company/{companyId}/data-points, mapped
GET /partner/{partnerCode}/company/{erpCompanyId}/benchmark/real-estateNone: it stops working at the sunset

For the emissions and portfolio operations, change /v1 or /v2 to /v3 and you’re done.

API keys

Your existing API keys work on v3. What each key may do is shown in the Scopes column of the API keys page API keys page . Keys created before scopes were introduced show company:read, data-point:write and benchmark:read: they can list companies and upload data, but not read emissions or portfolios. For those, create a new key with emissions:read or portfolio:read.

The older sign-in flow, which exchanged a secret for a temporary token at POST /v1/auth/generate-token, and GET /v1/emissions/organization/… have been retired. Use an API key as described in Authentication.

Errors

Every error from v3 is in the Problem Details format, with a stable code and per-field errors: see Errors and limits. v1 and v2 keep their current error bodies until the sunset.

A revoked API key is a 401 on v3, where v1 and v2 answer 400.

Company list

GET /v3/company returns:

{ "data": [{ "id": "1042", "name": "Energi.AI AS", "orgNumber": "927611074" }], "meta": { "nextCursor": null } }
  • The companies are in data, ordered by id, instead of list.
  • total is gone: count data instead.
  • orgNumber is null when unknown.
  • A query parameter is a 400: the list takes none.

Data-point upload

POST /v3/company/{companyId}/data-points takes { "data": [...] } with 1 to 500 records, and stores all of them or none: see Upload data. Compared with the v2 body:

v2v3
cost + currencycost: { "amount": …, "currency": … }, with an ISO 4217 currency
usageAmountusage (usageUnit stays)
vendorOrgNum, customerOrgNumvendorOrgNumber, customerOrgNumber
vendorCountryCode, customerCountryCodeSame names, but must be ISO 3166-1 alpha-2
date, dateToA date (YYYY-MM-DD) or a UTC timestamp ending in Z. dateTo is inclusive and may not be before date; with dateTo, any time of day is dropped
Up to 1,000 recordsUp to 500 records
dimensionsAt most 10 per record

Also:

  • At least one of cost, usage and productQuantity is still required.
  • correlationId may not be empty: leave it out for a record without a key.
  • A record whose correlationId the company already has replaces the stored record, as on v1 and v2. A field you leave out is cleared, so send records whole.
  • A correlationId repeated within one upload is a 400 (DUPLICATE_CORRELATION_ID).
  • A record that would change a locked record is a 409 (DATA_LOCKED), and nothing is stored. v1 and v2 skip such a record without saying so. Sending a record unchanged is always safe: it answers 201 with the stored record’s id.
  • The 201 response lists every record’s index, correlationId and id, in request order.
  • A v2 field name sent to v3 is rejected as UNKNOWN_PARAMETER, so a missed rename never goes unnoticed.

Posting journal lines

The posting-journal-line upload has no v3 version. Send each journal line to the v3 data-point upload instead:

Posting journal linev3 record
lineDate, or transactionDate when there is nonedate
accountNocategory1
accountNamecategory2
amount + currencyCodecost: { amount, currency }
subEntryTitledescription
entryNo, subEntryIdentryNo, subEntryId
vendorOrgNo, vendorNamevendorOrgNumber, vendorName
customerOrgNo, customerNamecustomerOrgNumber, customerName
dimensions: [{ name, value }]dimensions: [{ type, value }]
  • Set correlationId to {companyId}_{date}_{entryNo}_{subEntryId}, with date as YYYY-MM-DD as in the table. That is the key the posting-journal-line upload gave each line, so re-sending a line through v3 updates it instead of adding a copy.
  • transactionDate (when lineDate is set), foreignAmount, foreignCurrencyCode and exchangeRate have no v3 field. None of them changed a calculation.
  • Don’t re-send journal lines dated in a locked period: they answer 409 (DATA_LOCKED), because the stored line carries details v3 doesn’t send.

Partner benchmark

GET /partner/{partnerCode}/company/{erpCompanyId}/benchmark/real-estate has no replacement and stops working at the sunset.

Last updated on