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

# Push SKU Quantities

> The recurring ERP feed: how many pieces of each SKU were placed on which market in which year. **Asynchronous** — the request stages an import job and returns `202` with a `jobId`; poll `GET /api/import-jobs/{jobId}` (needs `packaging:read`) until `status` is terminal. Row validation runs BEFORE staging, so a malformed batch is a `400` you see immediately, never a job that fails minutes later. At most 5000 rows (`413`), at least one row (`400`). Restatement is the norm: the upsert is idempotent on (`articleNumber`, `periodYear`, `market`). After each accepted batch every packaging unit's placed figure is recomputed as the sum of its linked SKUs' quantities; a figure a human entered in the app is **never** overwritten and surfaces in the job result's `conflicts`. The feed writes unit-level placements only — per-size figures are entered in the app and are neither read, overwritten nor cleared by a push. Requires `packaging:write`; customer workspace with the PPWR module enabled — see the guide.



## OpenAPI

````yaml POST /api/ppwr/quantities
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/quantities:
    post:
      summary: Push SKU Quantities
      description: >-
        The recurring ERP feed: how many pieces of each SKU were placed on which
        market in which year. **Asynchronous** — the request stages an import
        job and returns `202` with a `jobId`; poll `GET
        /api/import-jobs/{jobId}` (needs `packaging:read`) until `status` is
        terminal. Row validation runs BEFORE staging, so a malformed batch is a
        `400` you see immediately, never a job that fails minutes later. At most
        5000 rows (`413`), at least one row (`400`). Restatement is the norm:
        the upsert is idempotent on (`articleNumber`, `periodYear`, `market`).
        After each accepted batch every packaging unit's placed figure is
        recomputed as the sum of its linked SKUs' quantities; a figure a human
        entered in the app is **never** overwritten and surfaces in the job
        result's `conflicts`. The feed writes unit-level placements only —
        per-size figures are entered in the app and are neither read,
        overwritten nor cleared by a push. Requires `packaging:write`; customer
        workspace with the PPWR module enabled — see the guide.
      operationId: pushPpwrQuantities
      requestBody:
        required: true
        content:
          application/json:
            schema:
              oneOf:
                - type: array
                  items:
                    $ref: '#/components/schemas/PpwrQuantityRow'
                  minItems: 1
                  maxItems: 5000
                  description: Bare array form — no `replaceScope`.
                - $ref: '#/components/schemas/PpwrQuantityIntakeInput'
      responses:
        '202':
          $ref: '#/components/responses/BatchAccepted'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '413':
          $ref: '#/components/responses/PayloadTooLarge'
        '500':
          $ref: '#/components/responses/InternalError'
components:
  schemas:
    PpwrQuantityRow:
      type: object
      description: >-
        One placed-quantity row for `POST /api/ppwr/quantities`. Upsert key:
        (`articleNumber`, `periodYear`, `market`) — re-pushing a period with
        corrected numbers is the normal flow.
      required:
        - articleNumber
        - periodYear
        - market
        - quantity
      properties:
        articleNumber:
          type: string
          description: >-
            Internal article number of an existing article. An unknown number is
            the row error `unknownArticleNumber`; a key repeated inside one
            batch is first-seen-wins plus `duplicateInFile` on the later rows.
        periodYear:
          type:
            - integer
            - string
          minimum: 2000
          maximum: 2100
          description: Calendar reporting year.
        market:
          type: string
          pattern: ^[A-Za-z]{2}$
          description: ISO alpha-2 market code (case-insensitive, stored upper-case).
        quantity:
          type:
            - number
            - string
          description: >-
            Pieces placed on that market in that year. Required and non-negative
            — a blank quantity is a broken feed row, not zero.
    PpwrQuantityIntakeInput:
      type: object
      description: Envelope form for the quantity feed. At least one row is required.
      required:
        - rows
      properties:
        rows:
          type: array
          items:
            $ref: '#/components/schemas/PpwrQuantityRow'
          maxItems: 5000
        replaceScope:
          type: string
          enum:
            - period-market
          description: >-
            Declares the batch the authoritative snapshot of every `(periodYear,
            market)` pair it mentions: stored rows in exactly those scopes that
            the batch omits are deleted. Other scopes are never touched. Omit it
            for a delta feed. Any other value is a `400`.
    ImportJobAccepted:
      type: object
      description: >-
        Batch import staged as an async job. Nothing is imported yet — poll
        `statusUrl` for progress and the final result.
      properties:
        jobId:
          type: string
          format: uuid
        status:
          type: string
          enum:
            - queued
        statusUrl:
          type: string
          example: /api/import-jobs/6f7a…
      required:
        - jobId
        - status
        - statusUrl
    ErrorResponse:
      type: object
      properties:
        error:
          type: string
        details:
          description: Additional error details (e.g. validation issues)
      required:
        - error
  responses:
    BatchAccepted:
      description: >-
        Batch accepted — async import job staged. Nothing imported yet; poll the
        job.
      headers:
        Location:
          description: URL of the import job to poll
          schema:
            type: string
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ImportJobAccepted'
    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'
    PayloadTooLarge:
      description: >-
        Batch exceeds the row cap. Nothing staged — page the sync across
        multiple requests (orders: keep all lines of one order in the same
        request, see the Batch Import guide).
      content:
        application/json:
          schema:
            type: object
            properties:
              error:
                type: string
                enum:
                  - batchTooLarge
              maxBatchSize:
                type: integer
                example: 5000
    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>`.

````