Zum Hauptinhalt springen
Bestellungen (Einkauf und Verkauf) übertragen Sie mit POST /api/v1/orders und lesen sie mit GET /api/v1/orders zurück — zugeordnet über Ihre eigene orderNumber und mit den verknüpften DDS (ddsReferences). Im Stapelimport ist jede Zeile eine Bestellzeile; Zeilen mit derselben orderNumber bilden eine Bestellung, die idempotent über orderNumber abgeglichen wird. Diese Seite beschreibt die Regeln, die nur für Bestellungen gelten. Den allgemeinen Ablauf — Job anlegen, Status abfragen, Ergebnis abholen — beschreibt Stapelimport (asynchron). Lieferant, orderType und orderDate einer Bestellung stehen fest, sobald sie gespeichert ist. Eine Übertragung, die einen dieser Werte ändert, lässt diese Bestellung mit conflictingDuplicateOrderRows fehlschlagen. Ebenso schlagen Zeilen einer Bestellung fehl, die sich in einem Bestellfeld widersprechen (Lieferantenfelder, orderType, orderDate, DDS-Referenzfelder). Ein geändertes deliveryDate einer bestehenden Bestellung wird übernommen. Lieferdatum pro Position (Teillieferung). Zeilen einer Bestellung dürfen verschiedene deliveryDate tragen: Jede Position behält ihr eigenes Datum (lines[].deliveryDate beim Lesen), und das deliveryDate der Bestellung ist das früheste davon. Sobald eine Position datiert ist, wird das deliveryDate der Bestellung immer aus den Positionen abgeleitet — ein separat gesendetes deliveryDate wird dann ignoriert. Ein POST mit einem einzelnen Objekt legt eine neue Bestellung an. Gibt es die orderNumber schon, lautet die Antwort 409. Bevor Sie eine einzelne Bestellung erneut senden, suchen Sie sie mit GET /api/v1/orders?orderNumbers=<Nr>, oder senden Sie sie als Stapel mit einer Zeile — der lässt sich gefahrlos wiederholen. Das einzelne Objekt speichert lines[].positionId; gemischte oder wiederholte Positions-IDs antworten mit 400 und code (positionIdMixed, duplicatePositionId). PATCH /api/v1/orders/{id} antwortet ebenso, und ein PATCH, der die Bestellnummer auf eine bereits vorhandene ändert, antwortet mit 409.

Bestellungen: replaceLines und die Vollständigkeitsregel

Der Import einer Bestellung ersetzt alle ihre Zeilen. Eine Anfrage, die Bestellung O enthält, muss deshalb alle Zeilen von O enthalten. Werden die Zeilen einer Bestellung über mehrere Anfragen verteilt, würde die zweite Anfrage die zuvor importierten Zeilen löschen. Die Prüfung auf ersetzte Zeilen macht daraus einen lauten Fehler statt eines stillen Datenverlusts:
  • Standard (replaceLines fehlt oder ist nicht true): Würde der Stapel gespeicherte Zeilen löschen, schlägt der gesamte Job vor dem ersten Schreibvorgang fehl. Das error-Feld des Jobs ist ein Text, der JSON enthält — werten Sie ihn als JSON aus:
    Senden Sie die genannten Bestellungen mit allen ihren Zeilen erneut. Eine Ausnahme: Ändert ein anderer Schreibvorgang eine der Bestellungen, während der Job läuft, kann der Job mit diesem Schlüssel fehlschlagen, nachdem frühere Bestellungen desselben Jobs schon geschrieben wurden.
  • "replaceLines": true erlaubt das Ersetzen: Die gesendeten Zeilen werden maßgeblich, auch wenn dabei Zeilen entfallen. Der Wert muss das JSON-Boolean true sein, auf oberster Ebene neben rows. Der Text "true" gilt als nicht gesetzt, und ein reines Array von Zeilen kann den Wert nicht setzen.
  • Dieselbe orderNumber nie in zwei Anfragen, die gleichzeitig laufen: Jobs eines Unternehmens können parallel laufen, ihre Reihenfolge ist nicht garantiert, und am Ende könnten die Zeilen der älteren Anfrage gespeichert sein. Eine geänderte Bestellung erst erneut senden, wenn der vorige Job dafür completed oder failed erreicht hat.

Positionen (positionId)

Jede Zeile eines Stapelimports kann optional eine positionId tragen — die Positionsnummer der Zeile in Ihrem ERP (z. B. die SAP-Bestellposition 00010). Sie wird getrimmt und danach Zeichen für Zeichen verglichen (nicht numerisch, führende Nullen bleiben erhalten), maximal 64 Zeichen.
  • Zeilen mit positionId werden nie zusammengefasst. Zwei Zeilen desselben Artikels mit verschiedenen Positionsnummern bleiben zwei Zeilen; ohne positionId werden sie beim Abgleich als eine Zeile (Summe der Mengen) behandelt.
  • Ganz oder gar nicht pro Bestellung: Innerhalb einer Anfrage müssen alle Zeilen einer Bestellung eine positionId haben oder keine (positionIdMixed). Eine Positionsnummer darf pro Bestellung nur einmal vorkommen (duplicatePositionId). Beides lässt die gesamte Bestellung fehlschlagen, nichts davon wird geschrieben.
  • Abgleich: Beim erneuten Senden einer Bestellung wird jede Zeile über ihre positionId verglichen — eine geänderte Menge oder ein geänderter Artikel auf derselben Positionsnummer gilt als Änderung, eine fehlende Positionsnummer als entfernte Zeile (Prüfung auf ersetzte Zeilen, siehe oben).
  • Umstellung: Eine ohne Positionsnummern gespeicherte Bestellung, die erstmals mit positionId gesendet wird, gilt als vollständig ersetzt. Dasselbe gilt umgekehrt: eine mit Positionsnummern gespeicherte Bestellung, die ohne sie gesendet wird. Senden Sie diesen Import mit "replaceLines": true.
  • Rücklesen: GET /api/v1/orders liefert positionId an jeder Zeile zurück. DDS-Referenzen sind nicht mit Zeilen verknüpft: ddsReferences gehört zur ganzen Bestellung (siehe unten).

Bestellstatus (status)

GET /api/v1/orders liefert an jeder Bestellung ein Feld status mit einem von drei Werten. Der Status wird bei jedem Lesen neu abgeleitet, nie gespeichert:
  • notRelevant: Keine Zeile der Bestellung trägt einen EUDR-relevanten Artikel. Zeilen, deren Artikel gelöscht wurde, zählen nicht (sie fehlen auch in lines[]). Ein Artikel, dessen HS-Code noch auf die manuelle Prüfung der EUDR-Relevanz wartet (z. B. Position 9403), hält die Bestellung auf open, nicht auf notRelevant oder done; an dieser Zeile ist lines[].article.needsManualCheck true.
  • done: Jede EUDR-relevante Zeile ist durch eine eingereichte, validierte oder gruppierte DDS-Erklärung abgedeckt, die mit dieser Bestellung verknüpft ist und den Artikel der Zeile für den Lieferanten der Bestellung mit ausreichender Menge deklariert. Ein DDS-Eintrag ist ein Lieferantenartikel: Er deckt nur Bestellungen desselben Lieferanten und verbraucht nur deren Mengen. Die Menge des Artikels, summiert über alle mit dieser DDS-Erklärung verknüpften Bestellungen dieses Lieferanten, darf die deklarierte Menge nicht übersteigen — genau wie die Restmenge der DDS-Erklärung selbst. Eine Bestellung eines anderen Lieferanten, die manuell mit dieser DDS-Erklärung verknüpft wurde, bleibt open.
  • open: alles andere — auch eine Bestellung mit einem Artikel, der auf die manuelle Prüfung der EUDR-Relevanz wartet.
Eine erhöhte Menge, ein geänderter Artikel oder eine zurückgezogene bzw. abgelehnte DDS-Erklärung setzt done wieder auf open — einen eigenen Aufruf zum Wiedereröffnen gibt es nicht.
  • Freigabe einer Position (z. B. SAP-Sperre): Geben Sie eine Position nur frei, wenn
    1. der status der Bestellung done ist (jede EUDR-relevante Zeile ist durch eine eingereichte DDS-Erklärung abgedeckt) oder notRelevant, oder
    2. für eine einzelne Zeile lines[].article.eudrRelevant false und lines[].article.needsManualCheck false ist (der Artikel der Zeile ist nicht EUDR-relevant).
    Eine einzelne Position hat kein eigenes notRelevant. Entscheiden Sie immer auf Grundlage des aktuellen Abrufs, nie eines früheren. ddsReferences brauchen Sie erst nach dieser Entscheidung: für die TRACES-Referenz und die Verifizierungsnummer, die Sie auf die Dokumente drucken.
Geben Sie Ware nicht frei, weil ddsReferences nicht leer ist. ddsReferences gehört zur ganzen Bestellung und listet jede verknüpfte DDS-Erklärung, die nicht zurückgezogen oder abgelehnt ist — auch Entwürfe ohne referenceNumber, externe und archivierte Erklärungen. Trägt eine Bestellung mehrere Referenzen, sagt die API nicht, welche welche Position abdeckt.
  • status kann open sein, obwohl ddsReferences nicht leer ist. ddsReferences enthält jede verknüpfte DDS-Erklärung, die nicht zurückgezogen oder abgelehnt ist — auch Entwürfe, archivierte, externe, in Kontrolle befindliche und gelöschte (soft-deleted) Erklärungen sowie Erklärungen, deren deklarierte Menge überbucht ist; keine davon macht die Bestellung done. Lesen Sie die zu druckenden TRACES-Nummern aus ddsReferences (eine externe DDS-Erklärung macht eine Bestellung nie done, ihre Referenz steht also nur hier); sie gehören zur Bestellung, nicht zu einer Position. Lesen Sie status dafür, ob die ganze Bestellung abgedeckt ist.
  • Filter ?status=: nimmt genau einen Wert (open, done oder notRelevant) und darf nur einmal übergeben werden; alles andere ist ein 400.
  • Nicht jeder Statuswechsel ist für die Bestellung eine Änderung im Sinne von changedSince. Diese Ereignisse ändern status, ohne die Bestellung zu ändern: eine andere Bestellung erhöht ihre Menge auf derselben DDS-Erklärung, die EUDR-Relevanz eines Artikels ändert sich, die manuelle Prüfung eines Artikels wird abgeschlossen, ein Artikel der Bestellung wird gelöscht, die deklarierte Menge eines DDS-Artikels wird bearbeitet, ein Lieferantenartikel wird gelöscht, die Artikel einer abdeckenden DDS-Erklärung ändern sich. Lesen Sie zum Abgleich mit ?status=open&limit=1000 neu und blättern Sie mit offset, bis eine Seite kürzer als limit ist.
  • Das Löschen eines Lieferanten entfernt alle seine Bestellungen aus GET /api/v1/orders, auch aus dem Voll-Sync. Behandeln Sie eine Bestellung, die im Voll-Sync fehlt, als gelöscht.

Delta-Sync (changedSince)

Fragen Sie GET /api/v1/orders?changedSince=<Beginn Ihres letzten Abrufs minus einige Minuten>&limit=1000 ab (stündlich empfohlen). changedSince ist ein ISO-8601-Zeitstempel mit Zeitzone (Z oder ein Versatz, z. B. 2026-10-05T05:55:00Z) und darf nur einmal übergeben werden; alles andere ist ein 400. Eine volle Seite (1000 Bestellungen) heißt: Geänderte Bestellungen sind nicht mitgekommen. Blättern Sie im selben changedSince-Fenster mit offset, bis eine Seite kürzer als limit ist, und fragen Sie häufiger ab. Eine Bestellung kann auf zwei Seiten erscheinen, und eine Bestellung, die sich während des Blätterns ändert, erscheint im nächsten Delta erneut. Wird während des Blätterns eine Bestellung gelöscht, können sich die Seiten verschieben, sodass eine Bestellung übersprungen wird — der nächtliche Voll-Sync fängt sie auf. Ein changedBefore gibt es nicht; ein nächtlicher Voll-Sync fängt alles auf, was ein Delta verpasst hat: Gelöschte Bestellungen, Bestellungen eines gelöschten Lieferanten und entkoppelte DDS-Erklärungen erscheinen nie in einem Delta.

Artikelfelder in Bestellzeilen wirken nur beim Anlegen

hsCode und articleDescription werden nur gelesen, wenn articleNumber überhaupt keinen Artikel trifft — die Zeile legt ihn dann an (gezählt in autoCreated.articles; ein leerer oder Platzhalter-hsCode wie - lässt die gesamte Bestellung mit articleMissingHsCode fehlschlagen, die Nummer eines gelöschten Artikels mit articleDeleted). Bei einem vorhandenen Artikel werden beide Felder stillschweigend ignoriert (kein Hinweis im Ergebnis) — HS-Code und EUDR-Relevanz des Artikels bleiben unverändert. Artikelstammdaten ändern Sie über PATCH /api/v1/articles/{id} oder den Artikel-Stapelimport. Bei einem Artikel mit Pro-Bestellung-Kopien (siehe unten) ändert das nur die Vorlage: Die Kopien behalten ihren HS-Code und übernehmen die neue EUDR-Einstufung nur, wenn ihr HS-Code dem der Vorlage entspricht und ihre Bestellung mit keiner DDS-Erklärung verknüpft ist (außer zurückgezogenen oder abgelehnten).

HS-Code auf Bestellzeilen mit Pro-Bestellung-Kopien (hsCode)

Eine Bestellzeile kann statt auf den Artikel selbst auf eine Pro-Bestellung-Kopie des Artikels zeigen. Der Artikel ist dann eine Vorlage, und jede Bestellung erhält eine Kopie pro Artikel (zwei Zeilen desselben Artikels teilen sie sich); die internalArticleNr der Kopie lautet <Artikelnummer>#<Bestellnummer>. Ein Artikel ist eine Vorlage, wenn:
  • ein Einkaufsbestellungs-Import ihn angelegt hat — in jedem Arbeitsbereich, mit oder ohne die Einstellung unten;
  • er mit sourceScope: "perOrder" gesendet wurde;
  • die Arbeitsbereich-Einstellung „Bestellimport legt Pro-Bestellung-Kopien an“ aktiv ist (standardmäßig aus, wird auf Anfrage von Polygon One eingeschaltet) und eine Zeile einer Einkaufsbestellung ihn nennt — außer einem Artikel mit einer externen Artikelnummer (vom Bestellimport angelegte Artikel tragen keine).
Eine neue Kopie startet mit dem HS-Code und der EUDR-Einstufung der Vorlage. Ohne die Einstellung wirkt hsCode auf einer bekannten Artikelnummer weiterhin nur beim Anlegen (siehe oben). Mit der Einstellung gilt für hsCode auf einer Zeile einer Einkaufsbestellung Folgendes:
  • Die Kopie trägt den HS-Code der Zeile. Weicht der HS-Code von dem der Vorlage ab, wird die EUDR-Relevanz neu berechnet; sonst bleibt die Einstufung der Vorlage erhalten. Eine Zeile ohne hsCode behält die Kopie, die sie hat, bzw. übernimmt den HS-Code der Vorlage.
  • Ein geänderter HS-Code verschiebt die Zeile auf eine andere Version. Senden Sie die Bestellung mit einem geänderten HS-Code erneut (verglichen ohne Trennzeichen, also 4407.11 = 440711), zeigt die Zeile auf die Version der Kopie dieser Bestellung, die diesen HS-Code hat. Eine neue Version entsteht nur, wenn es noch keine gibt; eine ältere Version mit diesem HS-Code wird samt ihren Lieferantendaten wiederverwendet. Eine neue Version startet ohne Lieferantendaten. Die übrigen Versionen bleiben unverändert.
  • Erneute Anfrage an den Lieferanten. Die Automatisierung „Auto-Einladung“ (automations.autoInviteSuppliers) lädt nach ihren eigenen Regeln ein: Ein Lieferant in einem EU-Land wird nicht eingeladen; ein Lieferant außerhalb der EU wird unabhängig von der Risikostufe seines Landes eingeladen, solange EUDR-relevante Daten fehlen; ein Lieferant ohne E-Mail-Adresse wird übersprungen (Sie erhalten eine Benachrichtigung); eine laufende Einladung, die Sie manuell zustellen, wird um die neue Version erweitert, aber nicht per E-Mail versendet. Ist die Herkunftsbestätigung pro Bestellung (automations.confirmOriginPerOrder) eingeschaltet und hat der Lieferant eine laufende Einladung, kann er zusätzlich eine Anfrage zur Herkunftsbestätigung erhalten. Diese Anfrage richtet sich nach dem Artikel, nicht nach dem HS-Code: Sie kann für die neue Version „Herkunft unverändert“ anbieten, gestützt auf eine früher beantwortete Kopie.
  • Unveränderter HS-Code: Eine identische erneute Übertragung ändert nichts — keine neue Version, keine neue Anfrage.
  • Widersprüchliche HS-Codes: Nennen zwei Zeilen einer Bestellung denselben Artikel mit unterschiedlichen HS-Codes — oder hat eine gleichzeitige Übertragung dieselbe Version mit einem anderen HS-Code angelegt —, schlägt die Bestellung mit conflictingHsCodeForArticle fehl.

Herkunft pro Bestellung per ERP

Mit Pro-Bestellung-Kopien (siehe oben) zeigt jede Bestellzeile auf eine eigene Kopie des Artikels, deren internalArticleNr <Artikelnummer>#<Bestellnummer> lautet. Ein ERP kann diese Kopie direkt befüllen, ohne Lieferantenportal:
  1. Kopie finden. Entnehmen Sie sie GET /api/v1/orders → lines[].article (id und supplierLinks: [{ supplierId, supplierArticleId }]). Sie können auch GET /api/v1/articles?internalArticleNr=<Nr>%23<Bestellnummer> abfragen (exakter Treffer; # als %23 kodiert); nach einem HS-Wechsel liefert das einen Artikel pro Version — nehmen Sie den, auf den die Bestellzeile zeigt.
  2. Parzellen. POST /api/v1/plots mit supplierArticleIds: [<supplierArticleId>] (plots:write).
  3. Nachweise. POST /api/v1/evidence/upload-url mit { fileName, contentType, fileSize } → die Bytes per PUT an uploadUrl (gleicher Content-Type, genau fileSize Bytes, sonst 403, innerhalb von 10 Minuten) → POST /api/v1/evidence als multipart/form-data mit supplierId, articleId (die ID der Kopie), uploadedS3Key (der zurückgegebene s3Key), uploadedFileName, uploadedFileSize, uploadedMimeType (evidence:write). Dieser Weg nimmt Dateien bis 10 MB an. Das Feld file statt der uploaded*-Felder nimmt höchstens 4 MB an (eine größere Datei ist ein 400). Was gespeichert ist, listet GET /api/v1/evidence?supplierArticleId=<id> (evidence:read). Dieselbe Datei an weitere Lieferantenartikel hängen: nicht erneut hochladen, sondern POST /api/v1/evidence je Ziel nur mit supplierId, articleId und reuseS3Key (der s3Key aus der ersten erfolgreichen Antwort) senden, optional mit evidenceType oder note. Jeder Aufruf legt einen eigenen Nachweis an diesem Artikel an.
Unter v1 gehören nur POST /api/v1/evidence/upload-url, POST /api/v1/evidence und GET /api/v1/evidence zum Vertrag. Löschen und erneutes Analysieren von Nachweisen sind für API-Schlüssel nicht verfügbar (403; der Body ist { "error": "Not available for API keys" }, oder { "error": "Forbidden" }, wenn dem Schlüssel die Berechtigung des Endpunkts fehlt). Die Schlüssel-Vorlage ERP-Anbindung enthält plots:write und evidence:write. Einem Schlüssel, der vor dem 1. Oktober 2026 mit dieser Vorlage angelegt wurde, fehlen sie: Prüfen Sie die Berechtigungen des Schlüssels oder legen Sie einen neuen an. Ein so übertragenes Dokument ist ein vom Käufer erstellter Nachweis (erfasst als hochgeladen vom Benutzer des API-Schlüssels); ein Upload des Lieferanten über das Portal hat die stärkere Herkunft.

Herkunft vom Lieferanten bestätigen lassen

Sind alle aktuellen Parzellen (und Nachweise) einer Bestellung hochgeladen, lassen Sie den Lieferanten diese Herkunftsdaten bestätigen:
  • Auswahl: jede supplierArticleId aus lines[].article.supplierLinks dieser Bestellung — eine aktive Verknüpfung eines EUDR-relevanten Artikels der Bestellung mit ihrem Lieferanten. Die Prüfung gilt für alle oder keine: Ist eine ID ungültig, wird nichts eingereiht.
  • Antwort: 202 { "status": "queued", "orderId", "supplierArticleCount" }. Die Anfrage an den Lieferanten und ihre E-Mail entstehen asynchron. Ein wiederholter Aufruf wird in die laufende Anfrage zusammengeführt und verschickt keine weitere E-Mail.
  • Was der Lieferant bestätigt: die aktuellen Herkunftsdaten dieser Bestellung. Daten früherer Bestellungen werden nie übernommen, und die Urheberschaft Ihrer hochgeladenen Daten bleibt unverändert.
  • Voraussetzungen: orders:write, und die Herkunftsbestätigung pro Bestellung (automations.confirmOriginPerOrder) ist für Ihren Arbeitsbereich eingeschaltet.