Order sync
ERP to Polygon One, and the DDS references back — the main EUDR flow. Your ERP pushes master data and orders; in Polygon One the orders are linked to due diligence statements (DDS); your ERP reads back, per order and position, whether the order is covered and which TRACES reference belongs to it.Push master data first: suppliers, then articles
hsCode and articleDescription on an order row are only read when the
article does not exist yet (create-only).
Suppliers are upserted on externalSupplierId or name, articles on internalArticleNr. A purchase
article needs a supplier (supplierId or supplierName).202 with a jobId. Wait until the supplier job has finished before you send the
articles, and until the article job has finished before you send the orders (poll as in
step 3). Jobs of one workspace can run at the same time: an article row whose supplierName is
not stored yet creates a new supplier with only that name.Push orders as a batch — every line of an order in the same request
orderNumber form one order. Importing an order
replaces its whole line set, so a request that names an order must carry all of its lines. If
your ERP has position numbers, send them as positionId on every row of the order.quantity is the net mass in kilograms. At most 5,000 rows per request — page a larger sync
across several requests, keeping each order’s lines together.Poll the import job and store the result
status is completed or failed. Persist result on your side — the job record is deleted
~30 days after creation. Failed rows carry stable error keys in failed[].error.key. A
failed job carries its reason in error, a string; for lineReplacementRequired it holds
JSON with the orderNumbers — a request would have deleted stored lines: resend the listed
orders with their complete line sets.Delta-poll the orders on a schedule
changedSince = the start of your previous poll minus a few minutes (an ISO 8601
timestamp with Z or an offset), with limit=1000. Hourly is recommended. fields keeps the
response to what the decision in step 5 needs.changedSince
window with offset until a page is shorter than limit, and poll more often. An order can
appear twice; one that changes while you page comes back in the next delta.Decide per order and position
- Whether the whole order is covered:
status(done,openornotRelevant). An article awaiting the manual EUDR-relevance check keeps the orderopen. - Unblocking a position (e.g. an SAP block): release a position only when
- the order’s
statusisdone(every EUDR-relevant line is covered by a filed DDS) ornotRelevant, or - for a single line,
lines[].article.eudrRelevantisfalseandlines[].article.needsManualCheckisfalse(the line’s article is not EUDR-relevant).
- the order’s
- Which TRACES reference to print: only after that decision, from
ddsReferences(referenceNumber,verificationNumber), for the documents.
status can be open while ddsReferences is non-empty (e.g. a draft or an external DDS). A
withdrawn or rejected DDS drops out of ddsReferences, and the order comes back in the next delta.Run a nightly full sync as recovery
offset until a page is shorter than
limit. Treat an order missing from the full list as deleted.status changes do not move the order into a delta (e.g. another order raising its quantity
on the same DDS, or an article’s manual check being resolved). Re-read with ?status=open&limit=1000 to reconcile them, paging with offset
the same way.- Splitting an order across requests. The second request would delete the lines of the first;
the check fails the whole job with
lineReplacementRequiredinstead. Send complete line sets, or"replaceLines": truewhen the line set is meant to shrink. positionIdon some rows only. All rows of an order carry one, or none (positionIdMixed), and each only once per order (duplicatePositionId). An order stored without position ids that is sent with them for the first time needs"replaceLines": true.- Releasing goods on a reference. Release only on
statusor onlines[].article.eudrRelevantandlines[].article.needsManualCheckbothfalsein the current read — never becauseddsReferencesis non-empty, and never on an earlier read. - Stopping at a full delta page. The orders beyond it are not returned again unless they
change; page the window with
offset.
Variant: per-order origin from the ERP
An order line points at its own copy of the article when the article is a per-order template: an article a purchase-order import created, an article sent withsourceScope: "perOrder", or — with
the workspace setting “order import creates per-order copies” (off by default, switched on by
Polygon One on request) — an existing article a purchase-order row names. Your ERP can attach plots
and documents to that copy directly, without the supplier portal: find the copy, create plots with
its supplierArticleId, upload evidence. This needs plots:write and evidence:write; the ERP
integration key preset includes both (a key created with it before 1 October 2026 lacks them —
check its permissions). Steps and responses:
Per-order origin via ERP.
Once all current plots are uploaded, call POST /api/v1/orders/{id}/origin-confirmation with the
selected order-line supplierArticleIds; the supplier then confirms this order’s current origin
data. Previous-order data is never copied, and buyer authorship stays unchanged. Details:
Have the supplier confirm the origin.
Plots and geo analysis
Send a plot geometry, wait for the deforestation analysis, read the result, download the report. No article or supplier is needed — a plot with a commodity group is enough.Optional: check the geometry
valid with the codes create
would answer. commodityGroup is optional here, but if you send "wood" the dry run also
requires a scientific species, as create does. It does not check your plot limit.Create the plot
201 with the plot under created. Take created.id. 409 with
code: "PLOT_LIMIT_REACHED" means your plot limit or monthly quota is reached: nothing is
created, and a retry does not help.Poll the analysis status
analysisStatus is pending or in_progress:Download the report once
- Sending a
FeatureCollection. One request creates one plot — send each feature on its own. - Polling the report instead of the status. Every report call renders the PDF anew; download it once, when the result exists.
- No plot reference in
name. Samename,country, geometry andsupplierArticleIdsagain is recognised ("deduplicated": true) — that is what makes a retry safe. - No
country. Without it, the low-risk skip never applies and the plot is always analyzed.
PPWR volume reporting
A short form of the Integration recipe ERP to LUCID. Steps 1–3 are one-time master data; steps 4–6 are the recurring job. The master-data endpoints answer synchronously (200); the quantity feed is an import job. The articles (SKUs) must already exist in
Polygon One: create missing ones with POST /api/v1/articles (articles:write). An unknown article
number is an error row in article-links and in the quantity job.
Components with material and mass
Packaging units — always with an internalRef
internalRef always creates a new unit. notes is mandatory.Bill of materials and SKU links
POST /api/v1/ppwr/links, and articles (SKUs) to units with
POST /api/v1/ppwr/article-links, which reports an unknown article number as an error row.Recurring: push quantities per SKU, market and year
202 with a jobId — poll GET /api/v1/import-jobs/{jobId} as in the order sync. Each row’s
quantity is the absolute total for that SKU, year and market and replaces the stored value —
never send increments, returns or credit notes as rows of their own; net them into the total.
Send replaceScope: "period-market" when the batch is the complete list for every year and
market it names; leave the field out when the batch carries only the SKUs that changed.Generate the report
422 lists item by item which data is not declarable yet — fix, re-push, generate again.Fetch the file and upload it to LUCID
GET /api/v1/ppwr/mengenmeldung/{id}/xml:- Unit rows without
internalRef. Each repeat creates another unit. - Linking SKUs via the unit row’s
articleNumbers. An unknown article number there is skipped; the response only counts such numbers (articleNumbersUnmatched) and does not name them.POST /api/v1/ppwr/article-linksreports each one as an error row. - Overwriting a stored value without
overwrite: true. The whole batch is refused with409 overwriteRequired, nothing is written. - Expecting the feed to replace a hand-entered figure. It never does; affected units come back in
conflicts.
Before you go live
- Key permissions per flow. Order sync:
suppliers:write,articles:write,orders:write(Batch Import); per-order origin additionallyplots:writeandevidence:write; plots:plots:write(Geo analysis); PPWR:packaging:write, plusarticles:writeif you create the SKUs over the API (PPWR). Write permissions include read. The ERP integration key preset includes all of these (a key created with it before 1 October 2026 lacksplots:writeandevidence:write). - Modules and exports. A key acts as a user. The PPWR endpoints need the PPWR module for that
user. The plot report needs the EUDR module for that user and exports enabled for your workspace
(otherwise
403). - The rate limit is shared per IP. 1000 requests per 60 seconds per client IP, across all
/apipaths and including people using the web app from the same network. Spread scheduled jobs and use the batch endpoints (Rate limit). - Retry only what is safe to retry.
429with JSON and5xxwith exponential backoff and jitter; batch imports are safe to replay. A repeated single-object supplierPOSTanswers409(same name orexternalSupplierId). A repeated single-object orderPOSTanswers409, and so does renaming an order onto an existing order number — look the order up first, or send orders as one-row batches (Retries). - There is no sandbox. Every call acts on your live workspace (Not in v1).
- Log
x-vercel-idon every failed call — support needs it (Request reference). - Ignore unknown response fields. v1 adds fields over time (Versioning).