> ## Documentation Index
> Fetch the complete documentation index at: https://code.dcycle.io/llms.txt
> Use this file to discover all available pages before exploring further.

# Changelog

> Changes to the Dcycle API, newest first

Additive changes may ship without notice; anything that can break an integration is listed here first.

## 2026-10-09

* **Breaking:** activity dates must fall between 1970 and next year (until now any year was stored, e.g. `0100-01-01`
  or `2064-03-01`, and calculated for that year). A date outside the range answers `422`:
  [Create Wastes (v2)](/api-reference/wastes/create-v2) rejects the batch with `SCHEMA_INVALID`; the v1 creates and
  updates of wastes, purchases, shipments (`transport_date`), vehicle consumptions, invoices, business travels, hotel
  stays and employee periods answer a validation error on the date (`type: activity_date_out_of_range`); logistics
  requests (`shipment_date`) and recharges (`date`) answer `ACTIVITY_DATE_OUT_OF_RANGE`, and their bulk endpoints
  report it per record. [Create Waste](/api-reference/wastes/create) and the invoice create and replace also require
  `end_date` on or after `start_date`, and [Update Waste](/api-reference/wastes/update) checks it against the stored
  date when only one of the two is sent (`type: end_date_before_start_date`). On the invoice replace, the shipment
  update and [Update Waste](/api-reference/wastes/update) only a date you change is checked: resending a stored date
  unchanged (e.g. a 1969 record) is still accepted. On the other updates (purchases, vehicle consumptions, business
  travels, hotel stays, employee periods, logistics, legacy transport routes) every date you send is checked: saving a
  record whose stored date is outside the range requires correcting that date. Files uploaded for these categories
  report such a row as an error. Records you already stored are not changed.
* **Changed:** logistics requests created through the API (v1 and v2, single and bulk:
  [Create](/api-reference/logistics/create-request), [Create in bulk](/api-reference/logistics/create-requests-bulk))
  and the legacy `POST /api/v1/logistics/shipment` calculator, sent with `load_unit` `teu` or `feu`, now count
  10,000 kg per TEU and 20,000 kg per FEU (until now 20,000 and 40,000), the GLEC Framework / ISO 14083 default for a
  loaded container and the value file uploads already used. Requests stored before this date are not recalculated.
* **New:** [`POST /v2/facilities`](/api-reference/facilities/create-v2) creates up to 1,000 facilities in one request
  and answers `201` with them, in the order sent. All or nothing, idempotent (`Idempotency-Key`, with
  `Idempotent-Replayed: true` on a retry), `dry_run`. `country` is required and `address` is never geocoded.
* **New:** [`POST /v2/facilities/delete`](/api-reference/facilities/delete-v2) deletes up to 1,000 facilities with their
  invoices, wastes and waste water treatments, as an ingest job (`entity_type: facilities`, `operation: delete`).
* **Deprecated:** `POST /v1/facilities` and `DELETE /v1/facilities/{facility_id}`, superseded by the two above. They
  keep working and answer with `Deprecation` and `Link: rel="successor-version"` headers. No removal date yet.
* **Changed:** `/v2/facilities` errors are [problem details](/api-reference/errors), like the rest of v2.
* **Changed:** a purchase's `purchase_type` ([Create](/api-reference/purchases/create),
  [Update](/api-reference/purchases/update), [Get](/api-reference/purchases/get),
  [List](/api-reference/purchases/list)) follows the emission factor that prices it, and gains a third value,
  `average_data`: `spend_based` for EXIOBASE, `average_data` for a physical-unit database (e.g. ecoinvent),
  `supplier_specific` for a custom factor. The value you send is replaced by the one its factor implies, except on
  purchases priced with a `custom_emission_factor_id`: until now a purchase sent as `supplier_specific` without a
  custom factor came back `supplier_specific`; it now comes back with its factor's type (`spend_based` by
  default). Accept `average_data` wherever you read or filter by `purchase_type`.
* **New:** [`GET /v1/logistics/requests/unique-values`](/api-reference/logistics/requests-unique-values) supports
  `field=vehicle_type`: the TOC names (`<vehicle>_<type>`) your active shipments use, with counts, exactly as the
  `vehicle_type[]` filter of [List Logistics Requests](/api-reference/logistics/list-requests) takes them. The new
  `project_id` parameter narrows them to the shipments linked to a project.

## 2026-10-08

* **Changed:** shipments ([Create](/api-reference/transport/create), [Update](/api-reference/transport/update))
  accept a `quantity_transported` of up to 999,999,999.99999 (9 integer digits, 5 decimal places; until now
  9,999,999.999) and a section `kms_manual` with up to 6 decimal places (until now 2). Bulk uploads keep 5 weight
  decimals and 6 km decimals instead of rounding them to 3 and 2.
* **New:** [`GET /v2/imports/{import_id}/status`](/api-reference/imports/get-status) returns `sheets`, every sheet
  name of the uploaded workbook, and [Create Import Session](/api-reference/imports/create-session) returns them too
  when it resumes an existing session for the same file (until now `sheets` came empty there). Sessions created
  before this date return `[]`.

## 2026-10-07

* **Breaking (BETA):** `unit_id` is required on every record of [`POST /v2/wastes`](/api-reference/wastes/create-v2)
  and must be kilograms (`61743a63-ff70-459c-9567-5eee8f7dfd5c`), the unit the app's waste form uses. A waste
  priced with a `custom_ef_record_id` may also be in that record's unit. A record without a unit (`SCHEMA_INVALID`)
  or with another one (new code `UNIT_NOT_SUPPORTED`) is rejected with the batch (`422 BULK_RECORDS_REJECTED`).
  Until now tonnes, grams and pounds were accepted and calculated: convert them to kilograms. Volume, energy,
  distance or currency units were stored and then failed as `CALCULATION_FAILED`.
* **Changed (BETA):** [`ingest_job.finished`](/api-reference/webhooks/overview#events) is sent only for jobs
  submitted with an API key. A job a person starts while signed in to Dcycle (e.g. the app's waste form) notifies that
  person in the app instead, and its `source` is the new value `app`; jobs sent with an API key keep `api_bulk`.
* **New:** every webhook delivery records why its last attempt failed (`last_error_code`) and the start of what your
  server answered (`last_response_body`, up to 2 KB): see
  [Debugging a failed delivery](/api-reference/webhooks/overview#debugging-a-failed-delivery).
* **Fixed:** timestamps of webhook endpoints and deliveries end with `Z` (UTC), like the rest of v2; they came
  without it.
* **Fixed:** the app-wide rate limit answers `429` on the v2 resources as [problem details](/api-reference/errors)
  (`TOO_MANY_REQUESTS`), not as `{"detail": "Rate limit exceeded"}`.
* **Changed:** stationary combustion items of [file readings](/api-reference/files/readings) carry
  `printed_fuel_name`, the fuel product as printed, kept by [Update Reading](/api-reference/files/update-reading)
  when omitted. When the fuel read contradicts it (e.g. `TECNODIESEL E+10`, a diesel, read as petrol `e10`), the
  item's `stationary_fuel_id` is `null` and the fuel must be chosen before the record calculates.
* **Changed:** organizations below a project's organization see its dashboard in
  [`GET /v2/dashboard`](/api-reference/dashboards/list) and [`GET /v2/dashboard/{id}`](/api-reference/dashboards/get)
  when they were invited to it, organization by organization, and only with the widgets of the views they may see.
  Projects that still use the old "share with child organizations" setting keep sharing with every organization below
  until that setting is saved again in the app.
* **Fixed (docs):** the error-handling examples of [Create Wastes (v2)](/api-reference/wastes/create-v2) read the
  rejected records from `errors`. Until now they read `detail.records`, which moved on 2026-10-05: if you copied
  them, update your code.
* **Fixed:** the [OpenAPI document](/api-reference/openapi-sdks) declares every error as problem details
  (`application/problem+json`, schema `Problem`) instead of FastAPI's default validation body, and its descriptions
  are written for integrators. Regenerate your client so it parses errors correctly.
* **Docs:** [Create Wastes (v2)](/api-reference/wastes/create-v2#find-the-ids-you-send) lists where to find every id
  (facility, unit, LER and R/D codes), and the ingest job pages say what to do when a job stops making progress.
  The job status `failed` and the item status `skipped` are reserved: no job or item ends in them today.

## 2026-10-06

* **New:** [`POST /v1/hotel-stays/bulk-delete-by-filters`](/api-reference/hotel-stays/bulk-delete-by-filters)
  deletes every hotel stay matching the list's filters in one request, guarded by the list's `filter_hash`.
  `select_all_matching_enabled` on [`GET /v1/hotel-stays`](/api-reference/hotel-stays/list) is now always `true`.
* **New:** `source[]` and `uploaded_by[]` filters on [`GET /v1/hotel-stays`](/api-reference/hotel-stays/list)
  and `bulk-delete-by-filters`.

## 2026-10-05

* **Changed:** the [pending mobility survey export](/api-reference/employees/pending-survey-download) leaves out
  people who were most likely never asked about the period (ex-employees who left before it, and people uploaded
  afterwards in a list answered for other periods only), and a period longer than a year gets a sheet per
  year, counted from the period's start.
* **Deprecated:** `POST /v1/wastes`, superseded by [`POST /v2/wastes`](/api-reference/wastes/create-v2). It keeps
  working and now answers with `Deprecation` and `Link: </v2/wastes>; rel="successor-version"` headers. No removal
  date yet; it will be announced here with notice.
* **Deprecated:** `POST /v1/waste/bulk-delete`, superseded by [`POST /v2/wastes/delete`](/api-reference/wastes/delete-v2)
  (asynchronous, idempotent). Same headers, no removal date yet.
* **New:** [Errors](/api-reference/errors) in v2 follow RFC 9457 problem details (`application/problem+json`) for
  `/v2/wastes`, `/v2/ingest-jobs` and `/v2/webhook-endpoints`. **Breaking for those BETA endpoints:** rejected records
  moved from `detail.records` to `errors`, and validation errors from `detail` to `errors`.
* **New:** v2 timestamps are UTC with `Z` (`2026-10-05T09:35:07.921Z`).
* **New:** [`GET /v2/ingest-jobs`](/api-reference/ingest-jobs/list) lists your jobs; `POST /v2/wastes?dry_run=true`
  validates without writing.
* **Fixed:** `X-RateLimit-Limit` now reports the bucket capacity, so `X-RateLimit-Remaining` never exceeds it; the
  IETF `RateLimit` and `RateLimit-Policy` headers are added ([Rate limits](/api-reference/rate-limits)).
* **New:** [OpenAPI document](/api-reference/openapi-sdks) of the v2 API, for SDKs and Postman.
* **New:** [`POST /v2/wastes/delete`](/api-reference/wastes/delete-v2): asynchronous bulk delete as an ingest job.
* **New:** [Retry Webhook Delivery](/api-reference/webhooks/retry-delivery), and `api_version` in every event.

## 2026-10-01

* **New:** [Webhooks](/api-reference/webhooks/overview): signed `ingest_job.finished` events with retries.
* **Breaking (BETA):** `Idempotency-Key` is required on `POST /v2/wastes`; the same key with a different body is
  `422 IDEMPOTENCY_KEY_REUSED`.

## 2026-09-29

* **New:** [`POST /v2/wastes`](/api-reference/wastes/create-v2) (BETA): up to 5,000 wastes per request, validated
  as a whole, calculated asynchronously as an [ingest job](/api-reference/ingest-jobs/get).


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.