Prewave EUDR - Customers - Products API

Allows you to manage customer products, including creating, updating, linking/unlinking products, and deactivating products.

Work with this as data

Every API here is available over the APIs.io API and to AI agents over MCP.

MCP server

One button, every client — Claude, Cursor, VS Code and the rest.

https://apis.io/mcp

Tools for apis

7 MCP tools reach this
  • find_apisBrowse and filter every API in the catalog.
  • get_api_artifactsOne API's artifacts, grouped by type.
  • get_openapiThe primary OpenAPI for this API.
  • find_similar_apisAPIs that look like this one.
  • apis_io_searchSTART HERE — APIs, providers and tags for one query, each with its total.
  • resolveTurn a domain, URL or GitHub org into the provider it belongs to.
  • find_cohortsEvery scored population of providers in the catalog.
All 92 tools

Call it yourself

curl for this page
This API
curl "https://apis.io/api/v1/apis/prewave-eudr-customers-products-api"
All apis
curl "https://apis.io/api/v1/apis?limit=25"

Discovery needs no key. Ratings and market analysis are Pro.

Get an API key

Free tier, no email required.

A second provider on the same verified email joins the account you already have.

OpenAPI Specification

prewave-eudr-customers-products-api-openapi.yml Raw ↑
openapi: 3.0.1
info:
  title: Public Prewave Actions EUDR - Customers - Products API
  description: 'Documentation of the Public Prewave API.


    ## What''s New


    ### Q1 2026 — Supplier Management, User Management, Actions and Feed


    This quarter introduces major v2 upgrades, expanded administrative capabilities, and the new Actions API.


    - **Core Releases:** Deployed Supplier Management API v2 and Feed API v2, alongside the all-new Actions API.

    - **Enhanced Functionality:** Added robust identifier management, granular user and role configuration, and endpoints for managing supplier connection contacts.

    - ⚠️ **Required Migration:** Legacy v1 endpoints for Suppliers and Sites Upsert have been deprecated. Developers must migrate existing integrations to v2 by **May 31, 2027** (original deadline was December 31, 2026).


    📖 **[Read the Q1 2026 changelog](https://docs.prewave.com/en/articles/699847-q1-2026-public-api-updates)**


    ### Q2 2026 — Supplier Screening and External Scores


    We have expanded our v2 documentation to include comprehensive integration guidance for supplier screening and validation workflows and identifier-based external score ingestion.


    - **New Capabilities:** Added support for optional post-onboarding screening and validation during the create event.

    - **External Scores:** Batch POST for multiple supplier sites, per-site history GET, and event-type discovery GET (`/public/v1/scores/externals` and `/public/v1/scores/externals/event-types`). Documented in OpenAPI when enabled for your organization.

    - **Developer Resources:** Published new integration examples and detailed identifier validation rules to streamline your implementation process.


    📖 **[Read the Q2 2026 changelog](https://docs.prewave.com/en/articles/699849-q2-2026-public-api-updates)**


    ### Q3 2026 — Scores Webhooks


    To support event-driven architectures and eliminate the need for continuous API polling, we are introducing webhooks for score state changes later this year.


    - **Event-Driven Architecture:** Register webhook URLs to receive real-time HTTP payloads whenever a supplier''s score updates, so you can drive immediate mitigation responses without polling the API.

    - **Availability:** Comprehensive OpenAPI specifications and payload schemas will be published closer to the release date.

    - **Note:** Schemas and behaviors are subject to refinement prior to general availability.


    Documentation updates will be provided prior to release.


    ### Q4 2026 — Feed V2


    We are enhancing Feed API v2 with additional capabilities on top of the existing `GET /public/v2/feed` contract (see Q1 changelog and OpenAPI for the current Feed v2 integration).


    - **Availability:** Details will be announced before release.

    - **Note:** Schemas and behaviors are subject to refinement prior to the official release.


    Documentation updates will be provided prior to release.


    ---


    ## Authentication

    Prewave’s public api uses *API tokens* to authenticate against our RESTful service. We’ll provide you an *API-token* that each

    endpoint needs present as a http header.


    To pass the token in a request, simply add it as a header-parameter with

    * key = X-Auth-Token

    * value = api-token


    See an example in curl below where the api-token would be 12345678-90ab-cdef-1234-567890abcdef

    ```

    curl --request GET \

    --url https://REPLACE_WITH_SERVER/public/v1/target/prewave/3975230/alerts \

    --header ''X-Auth-Token: 12345678-90ab-cdef-1234-567890abcdef''

    ```


    ---


    ## Manage API Tokens


    Before you can obtain your API token, you''ll need the credentials for your API user. These credentials will be

    sent to you as part of the company-onboarding. If you haven''t got your credentials yet, please reach out to

    your sales-contact at Prewave or contact us via info@prewave.ai


    To generate an API Token, navigate to https://www.prewave.com/management/api and log in with the

    credentials of your API user. Then click at the button "Create New" and use your new api-token authentication as a header parameter.


    You can create multiple API tokens and also remove existing API tokens on https://www.prewave.com/management/api.

    API tokens do not expire, therefore you have to maintain the list of API tokens you are using manually.


    ---


    ## Default Rate Limits


    We have two types of default rate limits. For increased access, please contact customer success.


    | Type                              | Requests per 10 seconds | Requests per Minute |

    |-----------------------------------|-------------------------|---------------------|

    | GET requests                      | 100                     | 500                 |

    | POST, PUT, PATCH, DELETE requests | 20                      | 100                 |


    '
  version: '1.0'
servers:
- url: https://api.prewave.com
  description: Production Environment
security:
- Token authentication: []
tags:
- name: EUDR - Customers - Products
  description: Allows you to manage customer products, including creating, updating, linking/unlinking products, and deactivating products.
paths:
  /public/v2/eudr/customers/products/outbound/{productId}:
    put:
      tags:
      - EUDR - Customers - Products
      summary: Update an existing outbound product
      description: "\nUpdate an existing outbound product's information.\n\nAll product fields in the payload can be updated; changes are persisted immediately.\n\n**Required permission:** `access_public_products` and `UPDATE` on the product\n        "
      operationId: updateOutboundProduct
      parameters:
      - name: productId
        in: path
        description: The ID of the product.
        required: true
        schema:
          type: integer
          format: int32
        example: 301
      requestBody:
        description: Updated outbound product payload.
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/PublicOutboundProductPayload'
            examples:
              Update outbound product:
                summary: Revised name, reference, and HS code
                description: Update outbound product
                value: '{"name":"Oak Dining Table","scientificName":"Quercus robur","reference":"OUT-2025-001","hsCode":"940360","annualRevenue":null,"annualQuantity":null,"unit":null}'
        required: true
      responses:
        '200':
          description: Product updated successfully.
        '400':
          description: Errors if related data not found or invalid
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorDTO'
              examples:
                HS Code not found:
                  description: HS Code not found
                  value:
                    code: hs_code_not_found
                    message: 'HS code not found: HSCode=123456'
                    solution: Check if the identifier provided is correct or create the record first
                Supplier not found:
                  description: Supplier not found
                  value:
                    code: supplier_not_found
                    message: 'Supplier not found: ID=123456'
                    solution: Check if the identifier provided is correct or create the record first
                Missing product scientific name:
                  description: Missing product scientific name
                  value:
                    code: missing_wooden_product_scientific_name
                    message: Missing product scientific name for wooden product
                    solution: Provide a scientific name for wooden products
        '403':
          description: '403 Forbidden - Authentication or authorization failure. This status code is returned when: (1) the request lacks valid authentication credentials (missing or invalid X-Auth-Token header), or (2) the authenticated user does not have the required permission to access this resource.'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/AccessDeniedErrorDTO'
              examples:
                Access denied example:
                  summary: User lacks necessary permissions or authentication
                  value: "{\n        \"loggedIn\": true,\n        \"code\": \"access_denied\",\n        \"message\": \"Access denied: you don't have necessary permissions to access this resource\",\n        \"solution\": \"Contact support for appropriate permissions\"\n    }"
        '500':
          description: 500 Internal Server Error - An unexpected error occurred on the server. The request may or may not have been processed.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorDTO'
              examples:
                Error - Server Error:
                  summary: Unexpected server error
                  value: "{\n        \"code\": \"internal_error\",\n        \"message\": \"An unexpected error occurred\",\n        \"solution\": \"Please try again later or contact support\"\n    }"
        '429':
          description: '429 Too Many Requests - API rate limit exceeded. The request has been rejected because the rate limit for this endpoint has been exceeded. Default rate limits: GET requests - 100 per 10 seconds, 500 per minute; POST/PUT/PATCH/DELETE requests - 20 per 10 seconds, 100 per minute. For increased access, please contact customer success.'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ApiRateLimitResponse'
              examples:
                Rate limit exceeded example:
                  summary: API rate limit exceeded
                  value: "{\n        \"error\": \"API rate limit exceeded\",\n        \"message\": \"You have reached the maximum allowed requests. Please try again later or upgrade your plan for increased access\",\n        \"requestLimit\": 20,\n        \"requestCount\": 20,\n        \"limits\": [\n            {\n                \"requestLimit\": 20,\n                \"timeInSeconds\": 10\n            },\n            {\n                \"requestLimit\": 100,\n                \"timeInSeconds\": 60\n            }\n        ],\n        \"currentTime\": \"2026-01-15T10:30:00\",\n        \"nextResetAt\": \"2026-01-15T10:30:10\"\n    }"
  /public/v2/eudr/customers/products/inbound/{productId}:
    put:
      tags:
      - EUDR - Customers - Products
      summary: Update an existing inbound product
      description: "\nUpdate an existing inbound product's information.\n\nAll product fields in the payload can be updated; changes are persisted immediately.\n\n**Required permission:** `access_public_products` and `UPDATE` on the product\n        "
      operationId: updateInboundProduct
      parameters:
      - name: productId
        in: path
        description: The ID of the product.
        required: true
        schema:
          type: integer
          format: int32
        example: 301
      requestBody:
        description: Updated inbound product payload.
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/PublicInboundProductPayload'
            examples:
              Update inbound product:
                summary: Revised name, reference, HS code, and supplier
                description: Update inbound product
                value: '{"name":"Oak Wood Planks","scientificName":"Quercus robur","reference":"INB-2025-001","hsCode":"440799","annualSpend":null,"annualQuantity":null,"unit":null,"supplierId":102006215}'
        required: true
      responses:
        '200':
          description: Product updated successfully.
        '400':
          description: Errors if related data not found or invalid
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorDTO'
              examples:
                HS Code not found:
                  description: HS Code not found
                  value:
                    code: hs_code_not_found
                    message: 'HS code not found: HSCode=123456'
                    solution: Check if the identifier provided is correct or create the record first
                Supplier not found:
                  description: Supplier not found
                  value:
                    code: supplier_not_found
                    message: 'Supplier not found: ID=123456'
                    solution: Check if the identifier provided is correct or create the record first
                Missing product scientific name:
                  description: Missing product scientific name
                  value:
                    code: missing_wooden_product_scientific_name
                    message: Missing product scientific name for wooden product
                    solution: Provide a scientific name for wooden products
        '403':
          description: '403 Forbidden - Authentication or authorization failure. This status code is returned when: (1) the request lacks valid authentication credentials (missing or invalid X-Auth-Token header), or (2) the authenticated user does not have the required permission to access this resource.'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/AccessDeniedErrorDTO'
              examples:
                Access denied example:
                  summary: User lacks necessary permissions or authentication
                  value: "{\n        \"loggedIn\": true,\n        \"code\": \"access_denied\",\n        \"message\": \"Access denied: you don't have necessary permissions to access this resource\",\n        \"solution\": \"Contact support for appropriate permissions\"\n    }"
        '500':
          description: 500 Internal Server Error - An unexpected error occurred on the server. The request may or may not have been processed.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorDTO'
              examples:
                Error - Server Error:
                  summary: Unexpected server error
                  value: "{\n        \"code\": \"internal_error\",\n        \"message\": \"An unexpected error occurred\",\n        \"solution\": \"Please try again later or contact support\"\n    }"
        '429':
          description: '429 Too Many Requests - API rate limit exceeded. The request has been rejected because the rate limit for this endpoint has been exceeded. Default rate limits: GET requests - 100 per 10 seconds, 500 per minute; POST/PUT/PATCH/DELETE requests - 20 per 10 seconds, 100 per minute. For increased access, please contact customer success.'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ApiRateLimitResponse'
              examples:
                Rate limit exceeded example:
                  summary: API rate limit exceeded
                  value: "{\n        \"error\": \"API rate limit exceeded\",\n        \"message\": \"You have reached the maximum allowed requests. Please try again later or upgrade your plan for increased access\",\n        \"requestLimit\": 20,\n        \"requestCount\": 20,\n        \"limits\": [\n            {\n                \"requestLimit\": 20,\n                \"timeInSeconds\": 10\n            },\n            {\n                \"requestLimit\": 100,\n                \"timeInSeconds\": 60\n            }\n        ],\n        \"currentTime\": \"2026-01-15T10:30:00\",\n        \"nextResetAt\": \"2026-01-15T10:30:10\"\n    }"
  /public/v2/eudr/customers/products/outbound:
    get:
      tags:
      - EUDR - Customers - Products
      summary: Get a list of outbound products
      description: "\nRetrieve a paginated list of outbound products for EUDR compliance.\n\nOutbound products are products that your organization sells or distributes.\nEach item includes linked inbound product IDs when BOM relationships exist.\n\n**Use Cases**:\n- List all outbound products\n- Filter products by various criteria\n- Export product data for compliance reporting\n\n**Pagination**:\n- Results are paginated (default: 10 items per page)\n- Use `page` and `size` query parameters to control pagination\n\n**Required permission:** `access_public_products`\n        "
      operationId: findOutboundProducts
      parameters:
      - name: ids
        in: query
        description: Filter by product IDs. When set, other filters are ignored.
        required: false
        schema:
          type: array
          description: Filter by product IDs. When set, other filters are ignored.
          example:
          - 1
          - 2
          - 3
          items:
            type: integer
            description: Filter by product IDs. When set, other filters are ignored.
            format: int32
        example:
        - 1
        - 2
        - 3
      - name: q
        in: query
        description: Full text search query for outbound product names, references or linked inbound product names, references or suppliers.
        required: false
        schema:
          type: string
          description: Full text search query for outbound product names, references or linked inbound product names, references or suppliers.
          example: soy oil
        example: soy oil
      - name: page
        in: query
        description: Page number (0-based)
        required: false
        schema:
          type: integer
          default: 0
        example: 0
      - name: size
        in: query
        description: Page size
        required: false
        schema:
          type: integer
          default: 10
        example: 10
      responses:
        '200':
          description: Paginated list of outbound products.
          content:
            application/json:
              schema:
                type: object
                properties:
                  content:
                    type: array
                    items:
                      $ref: '#/components/schemas/PublicOutboundProduct'
                  size:
                    type: integer
                    format: int32
                  number:
                    type: integer
                    format: int32
                  totalElements:
                    type: integer
                    format: int32
                  totalPages:
                    type: integer
                    format: int32
                  numberOfElements:
                    type: integer
                    format: int32
                  first:
                    type: boolean
                  last:
                    type: boolean
                  empty:
                    type: boolean
              examples:
                Outbound products page:
                  summary: Outbound products with linked inbound product IDs
                  description: Outbound products page
                  value: '{"content":[{"id":101,"customerId":100,"orgId":200,"name":"Oak Dining Table","scientificName":"Quercus robur","reference":"OUT-2025-001","commodity":{"id":1,"name":"Timber"},"hsCode":{"code":"940360","description":"Wooden furniture of a kind used in the dining room","commodityId":1},"inboundProducts":[201,202]},{"id":102,"customerId":100,"orgId":200,"name":"Plywood Cabinet","scientificName":null,"reference":"OUT-2025-002","commodity":{"id":1,"name":"Timber"},"hsCode":{"code":"441510","description":"Plywood, veneered panels and similar laminated wood","commodityId":1},"inboundProducts":[203]}],"pageable":{"pageNumber":0,"pageSize":10,"sort":{"empty":true,"sorted":false,"unsorted":true},"offset":0,"paged":true,"unpaged":false},"totalPages":1,"totalElements":2,"last":true,"size":10,"number":0,"numberOfElements":2,"sort":{"empty":true,"sorted":false,"unsorted":true},"first":true,"empty":false}'
        '400':
          description: Invalid pagination or filter parameters.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorDTO'
              examples:
                Invalid page number:
                  description: Invalid page number
                  value:
                    code: invalid_request
                    message: Page number must be non-negative
                    solution: Provide a valid page number (0 or greater)
                Invalid page size:
                  description: Invalid page size
                  value:
                    code: invalid_request
                    message: Page size must be between 1 and 100
                    solution: Provide a valid page size
        '403':
          description: '403 Forbidden - Authentication or authorization failure. This status code is returned when: (1) the request lacks valid authentication credentials (missing or invalid X-Auth-Token header), or (2) the authenticated user does not have the required permission to access this resource.'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/AccessDeniedErrorDTO'
              examples:
                Access denied example:
                  summary: User lacks necessary permissions or authentication
                  value: "{\n        \"loggedIn\": true,\n        \"code\": \"access_denied\",\n        \"message\": \"Access denied: you don't have necessary permissions to access this resource\",\n        \"solution\": \"Contact support for appropriate permissions\"\n    }"
        '500':
          description: 500 Internal Server Error - An unexpected error occurred on the server. The request may or may not have been processed.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorDTO'
              examples:
                Error - Server Error:
                  summary: Unexpected server error
                  value: "{\n        \"code\": \"internal_error\",\n        \"message\": \"An unexpected error occurred\",\n        \"solution\": \"Please try again later or contact support\"\n    }"
        '429':
          description: '429 Too Many Requests - API rate limit exceeded. The request has been rejected because the rate limit for this endpoint has been exceeded. Default rate limits: GET requests - 100 per 10 seconds, 500 per minute; POST/PUT/PATCH/DELETE requests - 20 per 10 seconds, 100 per minute. For increased access, please contact customer success.'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ApiRateLimitResponse'
              examples:
                Rate limit exceeded example:
                  summary: API rate limit exceeded
                  value: "{\n        \"error\": \"API rate limit exceeded\",\n        \"message\": \"You have reached the maximum allowed requests. Please try again later or upgrade your plan for increased access\",\n        \"requestLimit\": 100,\n        \"requestCount\": 100,\n        \"limits\": [\n            {\n                \"requestLimit\": 100,\n                \"timeInSeconds\": 10\n            },\n            {\n                \"requestLimit\": 500,\n                \"timeInSeconds\": 60\n            }\n        ],\n        \"currentTime\": \"2026-01-15T10:30:00\",\n        \"nextResetAt\": \"2026-01-15T10:30:10\"\n    }"
    post:
      tags:
      - EUDR - Customers - Products
      summary: Create a new outbound product
      description: "\nCreate a new outbound product for EUDR compliance.\n\nOutbound products represent products that your organization sells or distributes.\nProvide at least `name` and `hsCode`; add `scientificName` and `reference` when available.\n\n**Required permission:** `access_public_products`\n        "
      operationId: addOutboundProduct
      requestBody:
        description: Outbound product creation payload.
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/PublicOutboundProductPayload'
            examples:
              Full product:
                summary: Outbound product with scientific name and reference
                description: Full product
                value: '{"name":"Oak Dining Table","scientificName":"Quercus robur","reference":"OUT-2025-001","hsCode":"940360","annualRevenue":null,"annualQuantity":null,"unit":null}'
              Basic product:
                summary: Minimum required fields (name and HS code)
                description: Basic product
                value: '{"name":"Oak Dining Table","scientificName":null,"reference":null,"hsCode":"940360","annualRevenue":null,"annualQuantity":null,"unit":null}'
        required: true
      responses:
        '200':
          description: Outbound product created successfully. Returns the ID of the newly created product.
          content:
            application/json:
              schema:
                type: integer
                description: ID of newly created product
              examples:
                Created product ID:
                  description: Created product ID
                  value: '301'
        '400':
          description: Errors if related data not found or invalid
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorDTO'
              examples:
                HS Code not found:
                  description: HS Code not found
                  value:
                    code: hs_code_not_found
                    message: 'HS code not found: HSCode=123456'
                    solution: Check if the identifier provided is correct or create the record first
                Supplier not found:
                  description: Supplier not found
                  value:
                    code: supplier_not_found
                    message: 'Supplier not found: ID=123456'
                    solution: Check if the identifier provided is correct or create the record first
                Missing product scientific name:
                  description: Missing product scientific name
                  value:
                    code: missing_wooden_product_scientific_name
                    message: Missing product scientific name for wooden product
                    solution: Provide a scientific name for wooden products
        '403':
          description: '403 Forbidden - Authentication or authorization failure. This status code is returned when: (1) the request lacks valid authentication credentials (missing or invalid X-Auth-Token header), or (2) the authenticated user does not have the required permission to access this resource.'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/AccessDeniedErrorDTO'
              examples:
                Access denied example:
                  summary: User lacks necessary permissions or authentication
                  value: "{\n        \"loggedIn\": true,\n        \"code\": \"access_denied\",\n        \"message\": \"Access denied: you don't have necessary permissions to access this resource\",\n        \"solution\": \"Contact support for appropriate permissions\"\n    }"
        '500':
          description: 500 Internal Server Error - An unexpected error occurred on the server. The request may or may not have been processed.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorDTO'
              examples:
                Error - Server Error:
                  summary: Unexpected server error
                  value: "{\n        \"code\": \"internal_error\",\n        \"message\": \"An unexpected error occurred\",\n        \"solution\": \"Please try again later or contact support\"\n    }"
        '429':
          description: '429 Too Many Requests - API rate limit exceeded. The request has been rejected because the rate limit for this endpoint has been exceeded. Default rate limits: GET requests - 100 per 10 seconds, 500 per minute; POST/PUT/PATCH/DELETE requests - 20 per 10 seconds, 100 per minute. For increased access, please contact customer success.'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ApiRateLimitResponse'
              examples:
                Rate limit exceeded example:
                  summary: API rate limit exceeded
                  value: "{\n        \"error\": \"API rate limit exceeded\",\n        \"message\": \"You have reached the maximum allowed requests. Please try again later or upgrade your plan for increased access\",\n        \"requestLimit\": 20,\n        \"requestCount\": 20,\n        \"limits\": [\n            {\n                \"requestLimit\": 20,\n                \"timeInSeconds\": 10\n            },\n            {\n                \"requestLimit\": 100,\n                \"timeInSeconds\": 60\n            }\n        ],\n        \"currentTime\": \"2026-01-15T10:30:00\",\n        \"nextResetAt\": \"2026-01-15T10:30:10\"\n    }"
  /public/v2/eudr/customers/products/outbound/{productId}/inbound:
    post:
      tags:
      - EUDR - Customers - Products
      summary: Connect inbound products to an outbound product
      description: "\nLink one or more inbound products to an outbound product.\n\nThese relationships are used for EUDR compliance tracking and origin request management.\n\n**Required permission:** `access_public_products` and `UPDATE` on the outbound product\n        "
      operationId: addOutboundInboundProducts
      parameters:
      - name: productId
        in: path
        description: The ID of the outbound product.
        required: true
        schema:
          type: integer
          format: int32
        example: 401
      requestBody:
        description: List of inbound product IDs to link to the outbound product.
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/PublicOutboundInboundProductPayload'
            examples:
              Link inbound products:
                summary: Connect three inbound products to one outbound product
                description: Link inbound products
                value: '{"inboundProductIds":[201,202,203]}'
        required: true
      responses:
        '200':
          description: Inbound products linked successfully.
        '400':
          description: Invalid list (duplicates or type mismatch).
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorDTO'
        '404':
          description: Outbound or inbound product not found.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorDTO'
        '409':
          description: Inbound product already linked.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorDTO'
        '403':
          description: '403 Forbidden - Authentication or authorization failure. This status code is returned when: (1) the request lacks valid authentication credentials (missing or invalid X-Auth-Token header), or (2) the authenticated user does not have the required permission to access this resource.'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/AccessDeniedErrorDTO'
              examples:
                Access denied example:
                  summary: User lacks necessary permissions or authentication
                  value: "{\n        \"loggedIn\": true,\n        \"code\": \"access_denied\",\n        \"message\": \"Access denied: you don't have necessary permissions to access this resource\",\n        \"solution\": \"Contact support for appropriate permissions\"\n    }"
        '500':
          description: 500 Internal Server Error - An unexpected error occurred on the server. The request may or may not have been processed.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorDTO'
              examples:
                Error - Server Error:
                  summary: Unexpected server error
                  va

# --- truncated at 32 KB (94 KB total) ---
# Full source: https://raw.githubusercontent.com/api-evangelist/prewave/refs/heads/main/openapi/prewave-eudr-customers-products-api-openapi.yml