> ## Documentation Index
> Fetch the complete documentation index at: https://help.polygon-one.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Changelog

> Changes to the Polygon One REST API, newest first

Within v1, changes are **additive only**: new endpoints, new fields and new optional parameters.
Existing fields are not removed or renamed (see [Versioning](https://help.polygon-one.com/en/api-reference/introduction.md#versioning)).
Your client must ignore fields it does not know. Breaking changes ship only as `/api/v2/`.

Entries marked **Changed** describe a change in behaviour, including one that refuses a request
that was accepted before; read them before you update an integration.

## 2026-10-20

* **New:** `ccEmails` (max. 10) is now supported when creating one supplier with
  `POST /api/v1/suppliers`. These contacts are copied on every email to the supplier; an address
  equal to `email` is ignored, and an invalid address rejects the request.
* **Changed:** production countries on article-supplier links are resolved from ISO alpha-2/alpha-3
  codes and localized country names on write, and read back as canonical English country names.
  Older or free-text values that cannot be resolved remain unchanged.

## 2026-10-19

* **New:** PPWR packaging-unit responses include the optional `recyclabilityReference` field: the
  free-text source on which the recyclability grade rests.
* **Changed:** `POST /api/v1/dds-statements` automatically partitions deliveries above the TRACES
  limits into a DDS group. The `201` response includes `memberIds`; every member must be submitted and
  validated before the group head can be submitted.
* **New:** a DDS delivery that cannot be partitioned returns `422` with
  `dds_partition_producer_too_large` or `group_volume_too_small`. The optional manual compliance check
  can also refuse the request with `422 compliance_blocked` and the blocking articles; nothing is
  written on these responses.

## 2026-10-13

* **Changed:** `GET /api/v1/dds-statements` and `GET /api/v1/dds-statements/{id}`:
  `articles[].volume`, `articles[].remainingVolume`, `totalVolume` and `totalRemainingVolume` can be
  `null`. This happens only on external (upstream) statements whose reference was declared without a
  quantity. A `null` total means at least one line has no volume. Your own statements always carry a
  volume. Treat `null` as "not stated", never as 0.
* **Changed (app, EUDR):** suppliers declare an upstream DDS with the reference and verification
  number only; one reference covers all selected articles. The quantity per article is optional, in
  the supplier portal and in "Link external DDS".
* **New:** the components in `GET /api/v1/ppwr/units/{id}` carry `heavyMetalsValueKind`, as in
  `GET /api/v1/ppwr/components`.
* **Changed:** `heavyMetalsValueKind` has the value `below_detection`: all four heavy metals were
  not detected. `heavyMetalsMgPerKg` is then `null` (never `0`), and the value counts as conforming.
  Read `null` together with `heavyMetalsValueKind`, not as "unknown" on its own.
* **Changed (app, PPWR):** heavy metals: "all four not detected" is shown as "not detected —
  compliant", never as 0.
* **Changed (app, PPWR):** masses, dimensions, test methods and a printed "n.d." for the heavy-metal
  sum are applied from a document automatically when the document prints them plainly (labelled,
  with unit and axis); anything else waits for your review. A total weight that may include the
  contents waits; a packaging type read from a document always takes one click.
* **Changed (app, PPWR):** a plain PFAS declaration ("PFAS-free", "contains no PFAS", "PFAS are not
  intentionally added", a company's "… confirms that …") is applied automatically. An exception, a
  footnote, a named substance, a hedge ("largely", "to the best of our knowledge") or a lab result
  still waits for your review.
* **Changed (app, PPWR):** a printed test method (e.g. "IEC 62321-5:2013") is applied on its own —
  also beside a heavy-metals value the supplier entered themselves; the value itself is never
  overwritten.
* **Fixed (app, PPWR):** long lab reports are read in full instead of failing on the answer length.
  A limit of another regulation (e.g. RoHS, lead 1000 mg/kg) is no longer proposed as the PPWR
  heavy-metals limit.
* **Changed (app, EUDR):** legal and evidence documents: dates, parties, reference numbers and areas
  are filled only when the document prints them under a recognised label or in a certifying
  sentence; a self-certification ("X certifies that …") names X as the issuer, never as the holder.
  A value the document prints but whose shape our rules cannot confirm is checked by the AI against
  the passage: it fills itself only when the passage states it explicitly, else it waits for your
  review.
* **Changed (app, EUDR):** a legal or evidence document is read once per file and judged for each
  article copy by fixed rules. The analysis is faster, and copies of the same file in the same
  context get the same result. The printed holder is matched against the supplier and the declared
  producers, also across translations and transliterations; when it matches no party, the document
  blocks. When the document leaves open whether the named company is the holder, you get a review
  hint instead of a block. The certification body is never the holder of a certificate. A
  certification scheme that differs from the declared one is a review hint, not a block.
* **Changed (app, EUDR):** a legal document is expired when its printed expiry date lies before the
  end of the article's production period; with no production period, when it lies before today.
* **Fixed (app, EUDR):** a document submitted as evidence for a geo risk on several plots is checked
  against each plot's own country and commodity. Before, the result for one plot could be reused for
  another. A printed validity period counts up to its latest date.
* **Changed (app, EUDR):** legal compliance: categories that need no evidence, or whose requirement
  is already met, no longer show a declined document as an open item. The document stays visible as
  "Optional evidence – not used" or "Not used – requirement already met". Suppliers no longer get
  "Fix" hints for such documents.
* **Changed (app):** every document is read with Mistral OCR; PDFs up to 120 pages get full text
  recognition (was 40).

## 2026-10-09

* **New:** `GET /api/v1/readiness?resourceType&resourceId&action` evaluates one resource for exactly
  one action (`eudr.dds_draft.create`, `eudr.dds.submit`, `ppwr.supplier_reply.submit`,
  `ppwr.declaration.issue`): state, findings (at most 100) and the next permitted actions (at most
  20\). An explanatory snapshot, never an authorisation for a later write. Foreign and missing
  resources answer `404`, an unsupported combination `400 not_supported`.
* **New:** `GET /api/v1/ppwr/article-units?articleId|orderId` lists the packaging units linked to
  exactly one article or order, paged by `cursor` (`packaging:read`).
* **New:** the MCP server offers write tools: create articles, suppliers and orders, update orders,
  create DDS drafts, update external DDS metadata, and create or update PPWR components and packaging
  units and link them — plus the read tools `getReadiness` and `listPpwrArticleUnits`. No deletes,
  no invitations, no TRACES submission. See [AI assistants (MCP)](https://help.polygon-one.com/en/api-reference/ki-assistenten.md).

## 2026-10-07

* **New:** the public API accepts OAuth 2.1 access tokens issued by Polygon One for an authorised
  application acting on behalf of a user (authorization code + PKCE, dynamic client registration via
  `/.well-known/oauth-protected-resource`). The token carries that user's role and permissions, not
  API-key scopes. A consent screen shows the application and the requested access.
* **New:** MCP server at `https://app.polygon-one.com/api/mcp` for Claude, ChatGPT and Copilot
  Studio: 20 read-only tools, one per GET endpoint of the REST API (`listArticles`, `getOrder`,
  `listPpwrDeclarations` …). Sign in with OAuth or an API key. No writes, no DDS submission, no
  compliance decisions; 120 calls per minute per user and client; results above 1 MB are refused
  with a hint to narrow the query; file downloads are not available to assistants yet.
* **Changed:** endpoints that are not available for API keys (re-analysis triggers, support chat, AI
  import, partner logo, admin) refuse OAuth tokens too — "machine client" means both.
* **Changed:** a `Bearer` token that is not an `eudr_` key is now verified as an OAuth token and
  answers `401` when invalid; it no longer falls back to the browser session cookie.
* **Changed:** requests carrying any `Authorization: Bearer` header no longer receive a
  session-cookie refresh (`Set-Cookie`).
* **New:** writes made with an OAuth token are logged with the application's client id on the audit
  row (`metadata.oauthClientId`); a PPWR intake through an OAuth token gets field provenance `api`,
  like an API-key intake.
* **New:** `POST /api/v1/orders/{id}/origin-confirmation` accepts the order's selected
  `supplierArticleIds` after all current plots have been uploaded and queues the supplier's
  confirmation of that current origin data (`202`). Previous-order data is not copied and buyer
  authorship is preserved. See
  [Have the supplier confirm the origin](https://help.polygon-one.com/en/api-reference/orders.md#have-the-supplier-confirm-the-origin).
* **Fixed:** two batch imports (or an import and an edit in the app) that rewrite the lines of the
  same order at the same time no longer leave the order with the lines of both. The last rewrite
  wins; the order's lines are always exactly one request's set. Never send the same `orderNumber` in
  two in-flight requests.
* **Changed:** `PATCH /api/v1/plots/{id}` re-derives the commodity group from the new links: a plot
  whose group is unset or `non_relevant` takes the group of its new links, as on create (`wood` when
  any of them is wood); an explicit group never changes. A plot that is `wood` after the change needs
  a species with a scientific name — stored, or sent in the new optional `species` field — otherwise
  `400 plot_species_required`. A plot whose group changed after its analysis ran is re-analysed.
* **New (app):** an expired supplier invite link is shown as "Expired" on the supplier card, the
  progress sheet and the waiting cards, with a Resend that picks the right invite. The day-7 reminder
  revives an expired EUDR invite instead of skipping it.
* **New (app):** critical questionnaire answers are visible to the supplier before submit and to the
  buyer behind the red; a missing questionnaire country is named (chip, gaps sheet, viewer, Articles
  table).
* **Changed (app):** an update request you send about a questionnaire names the question and opens
  the supplier's form on it; system-sent requests stay unchanged.
* **Changed (app):** the buyer-review thread entry names the section and the countries; the gaps card
  never shows your own request as the supplier's reply.
* **Changed (risk engine; stored verdicts move on re-analysis only):** wood plots take the wood path
  on every branch; recurring disturbance alerts alone support HIGH only when the 2020 forest is at
  least 0.5 ha and the alert area at least 0.18 ha.
* **New (app):** suppliers whose EUDR articles were imported before the auto-invite automation was
  switched on, and who were never invited, are invited by a daily catch-up and at switch-on.
* **Changed — breaking for integrations that send an estimated size:**
  `POST /api/v1/evidence/upload-url` and `POST /api/v1/ppwr/documents/upload-url` sign `fileSize` into
  `uploadUrl`. The `PUT` must send exactly `fileSize` bytes, otherwise storage refuses it with `403`
  (before, `fileSize` was only checked when the URL was issued). `fileSize` must be an integer greater
  than `0`; `0` or a fraction answers `400 "Invalid file size."`. Send the file's exact byte count.
* **New (documented):** `POST /api/v1/evidence` takes `reuseS3Key`: the `s3Key` from an earlier
  successful response attaches the same stored file to another supplier article without uploading it
  again. Exactly one source (`file`, the `uploaded*` fields or `reuseS3Key`), otherwise `400`; a
  `reuseS3Key` your company does not own answers `403`.
* **Changed:** `POST /api/v1/articles/bulk-delete`, `POST /api/v1/suppliers/bulk-delete`,
  `POST /api/v1/orders/bulk-delete`, `PUT /api/v1/articles/{id}/inputs` and
  `POST /api/v1/articles/{id}/primary-producer` answer a body that is not a JSON object with
  `400 { "error": "Invalid JSON body" }` instead of `500`.

## 2026-10-06

* **New:** the API reference documents every field, examples and error bodies (including `429`).
* **Changed:** a malformed id in the path answers `400` (or the endpoint's `404`) instead of `500`.
* **Changed:** a request body that is not a JSON object answers `400` instead of `500`.
* **Changed:** validation errors return `details` as a list of issues (`path`, `message`, `code`) on
  every endpoint.
* **Changed:** a rejected evidence file answers with `error` (the `message` key stays).
* **Changed:** deleting a member of a grouped DDS answers `409 GROUP_MEMBER_DELETE_REFUSED` instead
  of `500`.
* **Changed:** a single `POST /api/v1/orders` stores `lines[].positionId`; mixed or repeated position
  ids answer `400` with `code` (`positionIdMixed`, `duplicatePositionId`). `PATCH` answers the same way.
* **Changed:** a single `POST /api/v1/orders` with an order number that already exists answers `409`
  instead of `500`.
* **Changed:** `GET /api/v1/suppliers` no longer returns the internal fields `deletedAt` and
  `retentionUntil` on embedded compliance results.
* **New (documented):** `GET /api/v1/ppwr/units/{id}` components carry eight further attributes
  (recycled-content source and method, contact sensitivity, heavy-metal and PFAS fields).
* **Changed:** an order with an article that still awaits the manual EUDR-relevance check reads
  `open`, not `notRelevant` or `done`. `lines[].article.needsManualCheck` shows which line.
* **Changed:** changing an order's number to one that already exists answers `409` (was `500`).
* **Changed:** plots (API keys only): a `supplierArticleIds` value that is not a list answers `400
  plot_supplier_article_ids_invalid` (was: plot created without links).
* **Changed:** plots (API keys only): without `commodityGroup`, a plot whose linked articles give no
  single commodity group answers `400 plot_commodity_group_required` (was: created, analysis failed).
* **Changed:** plots (API keys only): the wood-species rule and the point-area cap use the effective
  commodity group (sent, or derived from the links). A retry of a plot that is wood through its links
  needs `species`.
* **Changed:** PPWR units refused by the plan's unit quota are reported in `failed` with
  `packagingUnitQuotaReached` (were in `skipped`); a refused unit creates nothing, not even its supplier.
* **Changed:** on PPWR `links`, a blank `massGrams` with a `formatReference` keeps the stored per-size
  mass (was: deleted it).
* **Changed:** attaching a PPWR document answers `201` with `extractionQueued: false` when the analysis
  could not be queued (was `500` after the document was stored).
* **Changed:** the declaration PDF's `lang` is matched case-insensitively; an unsupported value
  answers `400` listing the supported codes (was: German).
* **Changed:** the technical-documentation PDF validates `lang` like the declaration PDF: an
  unsupported value answers `400` (was: German).
* **Changed:** in a PPWR import, a size row with an empty Supplier cell under a unit that names a
  supplier is accepted (was `conflictingSizeRow`); a size row keeps its own error when its unit fails.
* **New:** `POST /api/v1/ppwr/mengenmeldung/reports` uses the LUCID operator id stored for the
  workspace when the request omits it, and returns the `systemOperatorId` it used.
* **Changed:** the five PPWR yes/no flags (`contactSensitive`, `foodContact`, `placedUnderOwnBrand`,
  `modifiesConformity`, `reusable`) can be switched off through the import: a stated `no` is stored; a blank keeps the
  stored value. A size row that contradicts its unit row fails with `conflictingSizeRow`.
* **Changed:** `POST /api/v1/ppwr/formats` asks before it overwrites existing sizes: `409` with
  `error: "overwriteRequired"` and `confirmUpdateCount`; resend with `overwrite: true` (like units
  and components).
* **Changed:** `GET /api/v1/ppwr/declarations?changedSince=` also returns a declaration that was
  superseded, or whose `activeSpecIds` shrank because a newer declaration took over a unit.
* **New:** declarations carry `supersededAt`.
* **Changed:** a declaration's `pdfUrl` is `null` when the file cannot be served.
* **Changed:** volume report: a packaging unit counts its figure without size OR its per-size
  figures, never both. A unit holding both blocks the report with `placement_both_levels` until one
  level is cleared (this includes reusable units). Typed figures outrank the quantity feed, the feed
  outranks figures taken from orders.
* **Changed:** quantity feed: feed figures are computed whenever they are read — link and SKU
  changes apply without a re-push; they are placed per size when every linked SKU of a multi-size
  unit names a size, otherwise on the unit. `derived` / `cleared` / `conflicts` in the job result
  count packaging units of the touched period/market scopes. Every push is recorded in the audit log
  (one entry per push, with the job id and the API key). Pushes into one workspace are processed one
  at a time, so two pushes into the same period and market can no longer leave a mix of both.
* **Changed:** generating a volume report supersedes only the previous report **of the same type**
  for that year and market (an HJM1 no longer marks a filed HMM1 as superseded). Version numbers
  count per report type.
* **New:** `DELETE /api/v1/ppwr/tonnage?periodYear&market&zsvrCategory` removes a tonnage figure the
  API pushed; `404` when none, `409 manualOverridePresent` for a figure entered in the app.
* **Changed:** `GET /api/v1/evidence` honours `limit`, `offset` and `fields` (they were ignored);
  an unknown field or `limit` above 1000 answers `400`. Without them the full list is returned as
  before. Documents are returned oldest upload first.
* **Changed:** a re-analysis of a single plot keeps the previous result until the new one is
  written, also after a failed run (`analysisStatus` and `assessedAt` tell which run it belongs to).
* **Changed:** an idempotent plot repeat with an invalid `size` answers `deduplicated`; the dry run
  (`POST /api/v1/plots/validate`) answers `valid: false` with `PLOT_LIMIT_REACHED` at the plot limit.

## 2026-10-02

* **Changed:** when an order batch (`POST /api/v1/orders` with an array) creates an article for a
  purchase order, that article is now a per-order template in every workspace. The order line points
  at its own copy of the article, numbered `<internalArticleNr>#<orderNumber>`, so `lines[].article` in
  `GET /api/v1/orders` names that copy. Sale orders and existing articles are unchanged.
* **New:** PPWR unit rows accept `material` and `massGrams`. A new unit with a `material` and no
  `componentCodes` gets one main-part component. The response adds `mainPartsCreated` and
  `unitsWithoutComponents`.

## 2026-10-01

* **New:** read PPWR Declarations of Conformity — `GET /api/v1/ppwr/declarations`,
  `GET /api/v1/ppwr/declarations/{id}` and the PDF via `GET /api/v1/ppwr/declarations/{id}/pdf`.
  `GET /api/v1/ppwr/units?include=doc` adds `docState` and `activeDeclaration` per unit.
  See [Reading Declarations of Conformity](https://help.polygon-one.com/en/api-reference/ppwr.md#reading-declarations-of-conformity).
* **New:** EUDR evidence under v1 — `POST /api/v1/evidence/upload-url`, `POST /api/v1/evidence` and
  `GET /api/v1/evidence`, with the permissions `evidence:read` and `evidence:write`.
* **New:** articles carry `supplierLinks` (`[{ supplierId, supplierArticleId }]`).
* **New:** attach documents to PPWR units and components — `POST /api/v1/ppwr/documents/upload-url`
  and `POST /api/v1/ppwr/documents`. See [Uploading documents](https://help.polygon-one.com/en/api-reference/ppwr.md#uploading-documents).
* **New:** the **ERP integration** key preset includes `plots:write` and `evidence:write`. Keys created
  earlier keep their permissions.
* **Changed:** re-analysing a plot is no longer available to API keys —
  `POST /api/v1/plots/{id}/reanalyze` answers `403` (`"Not available for API keys"`).
* **Changed:** a workspace can have a plot limit and a monthly plot quota. When one is reached,
  `POST /api/v1/plots` answers `409` with `code: "PLOT_LIMIT_REACHED"` and creates nothing.
* **Changed:** exports can be switched off for a workspace. Downloads such as the plot report, the
  Declaration of Conformity PDF and the volume report file then answer `403` with
  `code: "EXPORTS_BLOCKED"`.
* **Changed:** an optional compliance check for DDS statements. When it is switched on for your
  workspace, `POST /api/v1/dds-statements` and `POST /api/v1/dds-statements/{id}/submit` answer `422`
  with `error: "compliance_blocked"` and `details.blockingArticles` while articles are not compliant.

## 2026-09-30

* **Changed:** `POST /api/v1/orders` with one object now stores `deliveryDate`. Before, the value was
  accepted and dropped.

## 2026-09-29

* **New:** geo analysis guide. `POST /api/v1/plots/validate` checks a geometry without creating a plot;
  `GET /api/v1/plots/{id}/report` returns the plot report as PDF. See
  [Geo analysis over the API](https://help.polygon-one.com/en/api-reference/geo-analysis.md).
* **New:** `GET /api/v1/plots/{id}` carries an `analysis` object with the result of the deforestation
  analysis.
* **Changed:** `POST /api/v1/plots` with an API key refuses lines, collections, coordinates with fewer
  than 4 decimal places and geometry that cannot be repaired — `400` with a `code`, nothing is written.
  It stores the normalised geometry and returns `deduplicated` and `warnings`.
* **Changed:** `plots` embedded in articles, suppliers and DDS statements lists distinct plots
  **without geometry**, at most 1000 entries; `plotsTruncated: true` means more exist. Articles
  embedded in a supplier carry no plots. Fetch a plot's geometry with `GET /api/v1/plots/{id}`.
* **Changed:** `POST /api/v1/orders` with one object refuses a `supplierId` of another company and an
  article id your company does not own (`400`).
* **New:** PPWR unit and size rows accept `supplierReference` (the supplier's article number).
* **Changed:** PPWR unit and component rows with an unknown `supplierName` now create a name-only
  supplier and link it (listed in `suppliersCreated`). Before, the row was stored without a supplier.

## 2026-09-26

* **Changed:** every list endpoint returns at most 100 rows when `limit` is not set (`limit` at most
  1000\). Page with `offset` until a page is shorter than `limit`. Exception: `GET /api/v1/evidence`
  returns every row and ignores `limit` and `offset`.
* **New:** guide for delta sync of orders with `changedSince`. See
  [Delta sync](https://help.polygon-one.com/en/api-reference/orders.md#delta-sync-changedsince).
* **New:** optional `positionId` on order rows (your ERP position number). See
  [Positions](https://help.polygon-one.com/en/api-reference/orders.md#positions-positionid).
* **New:** derived order `status` (`open`, `done`, `notRelevant`) and the `?status=` filter on
  `GET /api/v1/orders`.
* **New:** with per-order article copies enabled, `hsCode` on order rows can create a new version of
  the order's article copy.
* **Changed:** `ddsReferences` and the `hasDdsReference` filter drop withdrawn and rejected DDS
  statements.
* **Documented:** `hsCode` and `articleDescription` on order rows only apply when the row creates the
  article.

## 2026-09-24

* **New:** versioned paths `/api/v1/…`. Paths without a version (`/api/…`) stay a permanent alias.
  See [Versioning](https://help.polygon-one.com/en/api-reference/introduction.md#versioning).
* **New:** `fields` query parameter on every JSON `GET` endpoint (except `GET /api/v1/evidence`, which
  ignores it). See [Field selection](https://help.polygon-one.com/en/api-reference/introduction.md#field-selection-fields).
* **New:** the OpenAPI spec is generated from the application's own request and response contracts.

## 2026-09-23

* **New:** plots API — create, read, link and delete plots.
* **New:** `changedSince` filter on `GET /api/v1/orders`.
* **Changed:** `PATCH /api/v1/dds-statements/{id}` changes external DDS statements only; any other
  statement answers `404`.

## 2026-09-15

* **New:** read PPWR master data back — `GET /api/v1/ppwr/units`, `/units/{id}`, `/components`,
  `/components/{id}`.
* **Changed:** `PATCH /api/v1/orders/{id}` and `PATCH /api/v1/articles/{id}` ignore fields that cannot
  be changed.

## 2026-09-05

* **New:** PPWR packaging sizes — `POST /api/v1/ppwr/formats`. See [PPWR](https://help.polygon-one.com/en/api-reference/ppwr.md).

## 2026-08-17

* **New:** PPWR quantity feed (`POST /api/v1/ppwr/quantities`), tonnage (`POST /api/v1/ppwr/tonnage`)
  and volume reports (`/api/v1/ppwr/mengenmeldung/…`). See [PPWR](https://help.polygon-one.com/en/api-reference/ppwr.md).

## 2026-07-31

* **New:** link SKUs to PPWR units — `POST /api/v1/ppwr/article-links`.

## 2026-07-28

* **New:** filter and page `GET /api/orders` — `hasDdsReference`, `orderNumbers`, `limit` and `offset`.

## 2026-07-27

* **Fixed:** the base URL in the reference is `https://app.polygon-one.com`.

## 2026-07-12

* **New:** PPWR API — master-data intake for components, units and links
  (`POST /api/ppwr/components`, `/units`, `/links`). See [PPWR](https://help.polygon-one.com/en/api-reference/ppwr.md).
* **Changed:** batch imports of articles, suppliers and orders run asynchronously — `202` with a
  `jobId`, results via `GET /api/import-jobs/{jobId}`. A single object still answers `201`.

## 2026-06-16

* **New:** duplicate and plausibility warnings on article create (`409` with `warnings`,
  override with `acknowledgeWarnings`).


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