Skip to main content
Within v1, changes are additive only: new endpoints, new fields and new optional parameters. Existing fields are not removed or renamed (see 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).

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.
  • 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.
  • 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.
  • 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.
  • 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.
  • New: optional positionId on order rows (your ERP position number). See Positions.
  • 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.
  • New: fields query parameter on every JSON GET endpoint (except GET /api/v1/evidence, which ignores it). See Field selection.
  • 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.

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.

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.
  • 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).