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

# Create Article Links

> Create unit⇄article links — the whole SKU mapping in one request. Create-only and idempotent. An unknown article number or unit reference is a per-row error and nothing is created — unlike the unit intake's `articleNumbers` column, which skips unmatched numbers silently. 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/article-links
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/article-links:
    post:
      summary: Create Article Links
      description: >-
        Create unit⇄article links — the whole SKU mapping in one request.
        Create-only and idempotent. An unknown article number or unit reference
        is a per-row error and nothing is created — unlike the unit intake's
        `articleNumbers` column, which skips unmatched numbers silently. At most
        1000 rows per request (`400` otherwise). Requires `packaging:write`;
        customer workspace with the PPWR module enabled — see the guide.
      operationId: createPpwrArticleLinks
      requestBody:
        required: true
        content:
          application/json:
            schema:
              oneOf:
                - type: array
                  items:
                    $ref: '#/components/schemas/PpwrArticleLinkRow'
                  maxItems: 1000
                  description: Bare array form.
                - $ref: '#/components/schemas/PpwrArticleLinkIntakeInput'
      responses:
        '200':
          $ref: '#/components/responses/PpwrIntakeResult'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '500':
          $ref: '#/components/responses/InternalError'
components:
  schemas:
    PpwrArticleLinkRow:
      type: object
      description: >-
        One unit⇄article link for `POST /api/ppwr/article-links`. Create-only
        and idempotent on (`specInternalRef`, `articleNumber`). **An unknown
        article number or unit reference is a row error here** — unlike the unit
        row's `articleNumbers` column, which skips unmatched numbers silently.
      required:
        - specInternalRef
        - articleNumber
      properties:
        specInternalRef:
          type: string
          description: '`internalRef` of an existing packaging unit.'
        articleNumber:
          type: string
          description: The article's internal article number (the number IS the SKU).
        formatReference:
          type: string
          maxLength: 120
          description: >-
            Name a SIZE of this unit and the link records THAT size; omit it to
            link the whole unit. A reference naming no size of this unit is the
            row error `unknownFormatRef`.
    PpwrArticleLinkIntakeInput:
      type: object
      description: Envelope form for the article-link intake. Links are create-only.
      required:
        - rows
      properties:
        rows:
          type: array
          items:
            $ref: '#/components/schemas/PpwrArticleLinkRow'
          maxItems: 1000
    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
    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'
    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>`.

````