> ## 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.

# Komponenten anlegen & aktualisieren

> Bulk upsert of packaging components — the same engine, row schema, validation and idempotency as the in-app CSV/Excel importer. Upsert key: `code` plus the resolved supplier. Fill-only by default: an empty cell never clears a stored value, a cell that fills an empty field is applied automatically, and a cell that would overwrite a non-empty (including supplier- or AI-attested) value needs `overwrite: true` — without it the whole batch is refused with `409` and nothing is written. Provenance and evidence columns are never writable through this API. At most 1000 rows per request (`400` otherwise). Requires `packaging:write`; customer workspace with the PPWR module enabled — see the guide.



## OpenAPI

````yaml POST /api/ppwr/components
openapi: 3.1.0
info:
  title: Polygon One Compliance API
  description: >-
    API for integrating ERP systems with the Polygon One EUDR Compliance
    Platform. Allows management of Articles, Suppliers, Orders, and Due
    Diligence Statements (DDS). PPWR packaging master data, the SKU quantity
    feed and Mengenmeldung reports are covered by the PPWR groups.
  version: 1.0.0
servers:
  - url: https://app.polygon-one.com
    description: Production Server
security:
  - bearerAuth: []
paths:
  /api/ppwr/components:
    post:
      summary: Upsert Packaging Components
      description: >-
        Bulk upsert of packaging components — the same engine, row schema,
        validation and idempotency as the in-app CSV/Excel importer. Upsert key:
        `code` plus the resolved supplier. Fill-only by default: an empty cell
        never clears a stored value, a cell that fills an empty field is applied
        automatically, and a cell that would overwrite a non-empty (including
        supplier- or AI-attested) value needs `overwrite: true` — without it the
        whole batch is refused with `409` and nothing is written. Provenance and
        evidence columns are never writable through this API. At most 1000 rows
        per request (`400` otherwise). Requires `packaging:write`; customer
        workspace with the PPWR module enabled — see the guide.
      operationId: upsertPpwrComponents
      requestBody:
        required: true
        content:
          application/json:
            schema:
              oneOf:
                - type: array
                  items:
                    $ref: '#/components/schemas/PpwrComponentRow'
                  maxItems: 1000
                  description: Bare array form.
                - $ref: '#/components/schemas/PpwrComponentIntakeInput'
      responses:
        '200':
          $ref: '#/components/responses/PpwrIntakeResult'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '409':
          $ref: '#/components/responses/PpwrOverwriteRequired'
        '500':
          $ref: '#/components/responses/InternalError'
components:
  schemas:
    PpwrComponentRow:
      type: object
      description: >-
        One packaging-component row for `POST /api/ppwr/components`. Upsert key:
        `code` + resolved supplier. Cells are coerced exactly as the in-app
        CSV/Excel importer coerces them, so a JSON-native value and its string
        spelling are equivalent (`12` = `"12"`, `["plastic"]` =
        `"plastic;paper_board"`, `true` = `"yes"`/`"ja"`/`"1"`). An empty or
        omitted field is a no-op — it never clears a stored value. Cross-field
        rules (each rejects the row with the named key): a `recycledContentPct`
        above 0 requires `recycledContentSource` **and** `recycledContentMethod`
        (`recycledProvenanceRequired`); `foodContact` requires
        `contactSensitive` (`foodContactImpliesContactSensitive`); the five PFAS
        fields are only accepted on a food-contact component
        (`pfasOnlyFoodContact`).
      required:
        - code
        - name
        - materials
      properties:
        code:
          type: string
          maxLength: 120
          description: >-
            Your component code — the upsert key, compared byte-exact after
            trimming (`KAR-01` ≠ `kar-01`).
        name:
          type: string
          description: Component name.
        supplierName:
          type:
            - string
            - 'null'
          description: >-
            Resolved to one of your suppliers by fuzzy name match (case,
            umlauts, punctuation and legal-form tokens are ignored). A name that
            matches **two or more** distinct suppliers fails the row with
            `ambiguousSupplierName` — the import never guesses. A name that
            matches **none** (and a blank cell) resolves to *no supplier*: the
            record lands in your own bucket without a row error, and the
            supplier is never auto-created.
        materials:
          type:
            - array
            - string
          items:
            type: string
            enum:
              - plastic
              - paper_board
              - glass
              - metal
              - wood
              - composite
              - other
          minItems: 1
          description: At least one material. Also accepts a `;`- or `,`-delimited string.
        polymer:
          type:
            - string
            - 'null'
          enum:
            - pet
            - hdpe
            - ldpe
            - pp
            - ps
            - pvc
            - other
            - null
          description: Polymer type (plastics only).
        massGrams:
          type:
            - number
            - string
          description: Mass of ONE piece of this component, in grams.
        recycledContentPct:
          type:
            - number
            - string
          description: Recycled content, 0–100.
        recycledContentSource:
          type:
            - string
            - 'null'
          enum:
            - pcr
            - pir
            - null
          description: '`pcr` = post-consumer, `pir` = post-industrial.'
        recycledContentMethod:
          type:
            - string
            - 'null'
          enum:
            - physical
            - mass_balance
            - null
        contactSensitive:
          type:
            - boolean
            - string
          description: Contact-sensitive packaging. Blank = `false`.
        foodContact:
          type:
            - boolean
            - string
          description: Food-contact packaging. Blank = `false`. Implies `contactSensitive`.
        heavyMetalsMgPerKg:
          type:
            - number
            - string
          description: Sum of the four regulated heavy metals, mg/kg.
        heavyMetalsBasis:
          type:
            - string
            - 'null'
          enum:
            - test_report
            - supplier_declaration
            - not_substantiated
            - null
          description: Provenance of the heavy-metals claim.
        heavyMetalsMethod:
          type:
            - string
            - 'null'
          description: >-
            Annex VII d) measurement standard (free text, e.g. `CEN/CR
            13695-1`). Accepted on every component.
        pfasCompliant:
          type:
            - boolean
            - string
            - 'null'
          description: 'Tri-state: blank = unknown. Food-contact components only.'
        pfasBasis:
          type:
            - string
            - 'null'
          enum:
            - test_report
            - supplier_declaration
            - not_substantiated
            - null
          description: Provenance of the PFAS claim. Food-contact components only.
        pfasMethod:
          type:
            - string
            - 'null'
          description: PFAS measurement method (free text). Food-contact components only.
        pfasSumPpb:
          type:
            - number
            - string
          description: Measured PFAS sum in ppb. Food-contact components only.
        pfasTotalFluorineMgPerKg:
          type:
            - number
            - string
          description: >-
            Total fluorine in mg/kg — the screening route. Food-contact
            components only.
        notes:
          type:
            - string
            - 'null'
          description: Free-text notes.
    PpwrComponentIntakeInput:
      type: object
      description: Envelope form for the component intake.
      required:
        - rows
      properties:
        rows:
          type: array
          items:
            $ref: '#/components/schemas/PpwrComponentRow'
          maxItems: 1000
        overwrite:
          type: boolean
          default: false
          description: >-
            Authorises overwriting values that are already filled (including
            supplier- and AI-attested ones). Without it a batch containing any
            such change is refused with `409 overwriteRequired` and **nothing**
            is written.
    PpwrIntakeResult:
      type: object
      description: >-
        Result of a synchronous PPWR intake. **Partial accept:** valid rows
        commit even when other rows are `invalid` or `failed` — the one
        exception is the `409` overwrite gate, which is all-or-nothing.
        **Idempotent:** replaying an identical request changes nothing (matched
        rows return as `skipped`), except unit rows without `internalRef`, which
        are always creates.
      required:
        - imported
        - updated
        - skipped
        - failed
        - invalid
      properties:
        imported:
          type: integer
          description: ENTITIES created (units, components, links) — never sizes.
        updated:
          type: array
          items:
            type: string
          description: >-
            Identifiers of rows whose existing match changed. A size created on
            an existing unit appears as `<unit ref> / <size ref>`.
        skipped:
          type: array
          items:
            type: string
          description: Identifiers of rows that matched with nothing to change.
        failed:
          type: array
          items:
            $ref: '#/components/schemas/PpwrRowError'
          description: >-
            Rows the upsert engine rejected (unknown reference, ambiguous match,
            …). Its `error` values are stable machine keys.
        invalid:
          type: array
          items:
            $ref: '#/components/schemas/PpwrIndexedRowError'
          description: >-
            Rows rejected by schema validation before the engine ran. Most
            `error` values are stable machine keys, but a field with no custom
            message falls back to the validator's own English text — match on
            the key, fall back to displaying the string.
        sizesCreated:
          type: integer
          description: 'Unit intake only: sizes created for the rows'' units.'
        articleNumbersUnmatched:
          type: integer
          description: >-
            Unit intake only: distinct `articleNumbers` no live article matched.
            Skipped, never a row error.
        articleLinksCreated:
          type: integer
          description: 'Unit intake only: unit⇄article links created from `articleNumbers`.'
        componentLinksCreated:
          type: integer
          description: >-
            Unit intake only: unit⇄component links created from
            `componentCodes`.
        componentStubsCreated:
          type: integer
          description: >-
            Unit intake only: minimal placeholder components created for unknown
            `componentCodes`.
    ErrorResponse:
      type: object
      properties:
        error:
          type: string
        details:
          description: Additional error details (e.g. validation issues)
      required:
        - error
    PpwrOverwriteRequired:
      type: object
      description: >-
        The batch contains at least one change that would overwrite an
        already-filled value. Nothing was written — resubmit with `overwrite:
        true`, or drop those rows.
      required:
        - error
        - confirmUpdateCount
      properties:
        error:
          type: string
          enum:
            - overwriteRequired
        confirmUpdateCount:
          type: integer
          description: How many rows in the batch need confirmation.
    PpwrRowError:
      type: object
      description: >-
        A row the upsert engine rejected. Carries no `index` — the engine
        reports by identifier.
      properties:
        identifier:
          type: string
        error:
          type: string
          description: 'Stable machine key (clamped: anything unexpected becomes `dbError`).'
    PpwrIndexedRowError:
      type: object
      description: >-
        A row rejected before the upsert engine ran, reported by its position in
        the request.
      properties:
        index:
          type: integer
          description: 0-based position of the row in the request.
        identifier:
          type: string
        error:
          type: string
          description: >-
            Usually a stable machine key; a field with no custom message falls
            back to the validator's own English text.
  responses:
    PpwrIntakeResult:
      description: Intake result (partial accept — see the schema).
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/PpwrIntakeResult'
    BadRequest:
      description: Invalid request data
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorResponse'
    Unauthorized:
      description: Invalid or missing API key
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorResponse'
    Forbidden:
      description: Insufficient permissions for this resource
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorResponse'
    PpwrOverwriteRequired:
      description: Unconfirmed overwrite — nothing was written.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/PpwrOverwriteRequired'
    InternalError:
      description: Internal server error
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorResponse'
  securitySchemes:
    bearerAuth:
      type: http
      scheme: bearer
      bearerFormat: API Key
      description: >-
        API key generated in Settings > API Keys. Include as `Authorization:
        Bearer <key>`.

````