> ## Documentation Index
> Fetch the complete documentation index at: https://docs.emidat.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Update supplier product

> Full replacement of editable fields. Immutable `plant_id` and
`material_type` may be omitted or echoed from the current resource.
`external_id` is replaced: re-sending this product's own code
succeeds unchanged, while a code held by another active supplier product
returns `409`. See [External IDs](/external-ids).




## OpenAPI

````yaml PUT /v2/supplier-products/{id}
openapi: 3.1.0
info:
  title: Emidat API
  version: '2.0'
  description: >
    The Emidat API v2 lets manufacturers create products and supplier products

    programmatically — designed for ERP and system integrations.


    Authentication uses a simple API key (`X-API-Key` header). Keys are issued

    per manufacturer and managed in the Emidat dashboard.


    Keys follow the format `emidat-{key_id}-{secret}`, where `key_id` is a

    random public handle.


    **Onboarding steps** — performed once before creating products:

    - Plant and production process setup (via Emidat UI)

    - Your material codes → Emidat material types and plant codes → Emidat
    plants are mapped in your integration middleware during setup; at runtime
    you send your own codes and the middleware resolves them

    - Create supplier companies via `POST /v2/supplier-companies` — every
    supplier plant needs one, as `supplier_company_id` is required

    - Create supplier plants via `POST /v2/supplier-plants`, referencing a
    supplier company by its Emidat `id`

    - Create supplier products using your own `external_id`; reference them in a
    product's BOM by their Emidat `id` (from the create response, or resolved
    via `GET …?external_id=`)

    - (Optional) Create silos to merge same-type supplier products from
    different suppliers — reference by their Emidat `id` in a product's BOM


    **Preview endpoints** — the `Product Instances` and `Prechain Products` tags

    are in preview. They are live and supported, but their contract is not
    frozen:

    request and response shapes, field names, and error codes may still change
    in

    ways that break existing integrations, possibly without a deprecation
    period.
servers:
  - url: https://api.emidat.com
    description: Production
security:
  - ApiKeyAuth: []
paths:
  /v2/supplier-products/{id}:
    put:
      tags:
        - Supplier Products
      summary: Update supplier product
      description: |
        Full replacement of editable fields. Immutable `plant_id` and
        `material_type` may be omitted or echoed from the current resource.
        `external_id` is replaced: re-sending this product's own code
        succeeds unchanged, while a code held by another active supplier product
        returns `409`. See [External IDs](/external-ids).
      operationId: v2_supplier_products_update
      parameters:
        - name: id
          in: path
          required: true
          schema:
            type: string
            format: uuid
          description: UUID of the supplier product to update.
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/UpdateSupplierProduct'
            example:
              external_id: CEMENT-SUPPLIER-DE-001
              name: Portland Cement CEM I 42.5 R
              supplier_plant_id: a1b2c3d4-e5f6-7890-abcd-ef1234567890
              transport_route:
                truck_distance_km: 95
              epd_id: null
              hazardous_substances: []
              lifetime_years: null
              secondary_percentage: null
              moisture_content_percentage: null
      responses:
        '200':
          description: Updated supplier product.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/SupplierProduct'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          description: Supplier product not found.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '409':
          description: >-
            The `external_id` is already in use by another active supplier
            product.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '422':
          description: |
            Validation error, including a malformed path `id`, a body `id` that
            differs from the path, a `supplier_plant_id` that does not resolve,
            or an attempt to change `plant_id` or `material_type`.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '500':
          $ref: '#/components/responses/InternalServerError'
        '502':
          $ref: '#/components/responses/BadGateway'
components:
  schemas:
    UpdateSupplierProduct:
      type: object
      description: >
        Full replacement of editable fields. Every editable field is required
        and

        overwrites the stored value. Nullable fields accept `null` to clear
        them;

        `hazardous_substances` accepts `[]`. The immutable identity fields may
        be

        omitted or echoed from the current resource.
      required:
        - external_id
        - name
        - supplier_plant_id
        - transport_route
        - epd_id
        - hazardous_substances
        - lifetime_years
        - secondary_percentage
        - moisture_content_percentage
      properties:
        id:
          type: string
          format: uuid
          description: |
            Optional assertion of the resource ID. It must match the path `id`.
        plant_id:
          type: string
          format: uuid
          description: |
            Optional assertion of the current plant. A different value returns
            `422`.
        material_type:
          oneOf:
            - $ref: '#/components/schemas/EmidatMaterialType'
            - $ref: '#/components/schemas/CompositeMaterialTypeRef'
          discriminator:
            propertyName: category
            mapping:
              emidat-elementary:
                $ref: '#/components/schemas/EmidatMaterialType'
              custom-composite:
                $ref: '#/components/schemas/CompositeMaterialTypeRef'
          description: |
            Optional assertion of the current material type. A different value
            returns `422`.
        external_id:
          anyOf:
            - type: string
            - type: 'null'
          description: >
            Your own code for this supplier product. Overwrites the stored code;
            pass

            `null` to clear it. Must stay unique among your active supplier
            products —

            a code held by another returns `409` (see [External
            IDs](/external-ids)).
          example: CEMENT-SUPPLIER-DE-001
        name:
          type: string
          description: Name of the supplier product.
          example: Portland Cement CEM I 42.5 R
        supplier_plant_id:
          anyOf:
            - type: string
              format: uuid
            - type: 'null'
          description: >-
            UUID of the supplier plant. Create via `POST /v2/supplier-plants`.
            Pass `null` to clear.
        transport_route:
          description: >
            Replaces the transport route — distances from the supplier plant to
            your

            gate, one per modality (km). Pass `null` to clear.
          anyOf:
            - $ref: '#/components/schemas/TransportRouteInput'
            - type: 'null'
        epd_id:
          anyOf:
            - type: string
              format: uuid
            - type: 'null'
          description: EPD UUID linked to this supplier product. Pass `null` to remove.
        hazardous_substances:
          type: array
          description: |
            Hazardous substances in this material, each by CAS number and mass
            share. Replaces the full list; send `[]` for none.
          items:
            type: object
            required:
              - cas_number
              - percentage
            properties:
              cas_number:
                type: string
                example: 7732-18-5
              percentage:
                type: number
                exclusiveMinimum: 0
                maximum: 100
                description: Share of total mass, greater than 0 and up to 100.
                example: 2.5
        lifetime_years:
          anyOf:
            - type: number
            - type: 'null'
          description: Expected service life in years. Pass `null` to clear.
        secondary_percentage:
          anyOf:
            - type: number
            - type: 'null'
          description: Share of secondary (recycled) content, 0–100. Pass `null` to clear.
        moisture_content_percentage:
          anyOf:
            - type: number
            - type: 'null'
          description: Moisture content as a percentage. Pass `null` to clear.
    SupplierProduct:
      type: object
      required:
        - id
        - external_id
        - name
        - material_type
        - plant_id
        - supplier_plant_id
        - transport_route
        - epd_id
        - hazardous_substances
        - lifetime_years
        - secondary_percentage
        - moisture_content_percentage
        - unit
        - impacts_per_kg
        - transport_impacts_per_kg
        - secondary_datasets
        - created_at
      properties:
        id:
          type: string
          format: uuid
        external_id:
          anyOf:
            - type: string
            - type: 'null'
          description: Your own code for this supplier product, as provided on creation.
        name:
          type: string
          example: Portland Cement CEM I 42.5 R
        material_type:
          description: |
            What this supplier product is made of — an Emidat elementary or a
            composite, by reference. Discriminated by `category`. Resolve a
            `composite_id` with `GET /v2/composites/{id}`.
          oneOf:
            - $ref: '#/components/schemas/EmidatMaterialType'
            - $ref: '#/components/schemas/CompositeMaterialTypeRef'
          discriminator:
            propertyName: category
            mapping:
              emidat-elementary:
                $ref: '#/components/schemas/EmidatMaterialType'
              custom-composite:
                $ref: '#/components/schemas/CompositeMaterialTypeRef'
        plant_id:
          type: string
          format: uuid
          description: The plant's Emidat UUID.
        supplier_plant_id:
          anyOf:
            - type: string
              format: uuid
            - type: 'null'
          description: |
            UUID of the supplier plant this material is sourced from. Resolve it
            with `GET /v2/supplier-plants/{id}`.
        transport_route:
          description: >-
            Transport distances from the supplier plant to your gate, one per
            modality (km).
          anyOf:
            - $ref: '#/components/schemas/TransportRoute'
            - type: 'null'
        epd_id:
          anyOf:
            - type: string
              format: uuid
            - type: 'null'
        hazardous_substances:
          type: array
          description: >-
            Hazardous substances in this material, each by CAS number and mass
            share.
          items:
            type: object
            required:
              - cas_number
              - percentage
            properties:
              cas_number:
                type: string
                example: 7732-18-5
              percentage:
                type: number
                example: 2.5
        lifetime_years:
          anyOf:
            - type: number
            - type: 'null'
        secondary_percentage:
          anyOf:
            - type: number
            - type: 'null'
        moisture_content_percentage:
          anyOf:
            - type: number
            - type: 'null'
        unit:
          type: string
          enum:
            - M
            - M2
            - M3
            - KG
            - T
            - L
            - KWH
            - MJ
            - UNIT
            - METRIC TON*KM
          example: KG
        impacts_per_kg:
          anyOf:
            - type: array
              items:
                $ref: '#/components/schemas/Indicator'
            - type: 'null'
          description: >-
            Characterized cradle-to-gate impacts of this supplier product per
            kg. Null until computed.
        transport_impacts_per_kg:
          anyOf:
            - type: array
              items:
                $ref: '#/components/schemas/Indicator'
            - type: 'null'
          description: >-
            The transport portion of this product's impacts per kg. Null until
            computed.
        secondary_datasets:
          anyOf:
            - type: array
              items:
                $ref: '#/components/schemas/SecondaryDataset'
            - type: 'null'
          description: Background datasets used to compute the impacts.
        created_at:
          type: string
          format: date-time
    Error:
      type: object
      required:
        - msg
        - err_code
      properties:
        msg:
          type: string
          description: Human-readable explanation, for logs and operators. Do not parse it.
          example: supplier product requires a supplier plant
        err_code:
          type: string
          description: >
            Stable, machine-readable error code — branch on this, never on
            `msg`.

            The set may grow over time; treat an unrecognized code as

            non-retryable and surface it to an operator. The enum lists every

            code the platform can emit; only a subset is reachable per

            endpoint — see [Errors](/errors) for the actionable catalog.


            `LcaRecomputeJob.err_code` reports failures from this same `err_*`

            namespace. `LcaBlocker.err_code` does not — those values are a

            separate, disjoint set.
          example: err_supplier_product_missing_supplier_plant
          enum:
            - err_not_defined
            - err_not_found
            - err_not_valid
            - err_not_authenticated
            - err_permission_denied
            - err_declaration_not_completed
            - err_declaration_not_regenerable
            - err_epd_document_already_exists
            - err_invalid_product_ids
            - err_generate_products_limit
            - err_plant_missing_product_category
            - err_plant_incomplete_address
            - err_plant_incomplete_company_fields
            - err_plant_categories_not_covering_processes
            - err_plant_categories_not_covering_active_products
            - err_plant_invalid_category_id
            - err_plant_custom_electricity_mix_not_allowed
            - err_plant_electricity_mix_mismatch
            - err_plant_negative_electricity_values
            - err_plant_electricity_without_mix
            - err_electricity_plant_production_mismatch
            - err_lca_mass_balance
            - err_lca_allocation_data_incomplete
            - err_lca_production_output_mismatch
            - err_product_mass_larger_than_recipe_mass
            - err_product_category_not_allowed_at_plant
            - err_water_not_scoped_but_wastewater_is_scoped
            - err_more_wastewater_than_water
            - err_project_no_products
            - err_invalid_product_quantity
            - err_duplicate_product
            - err_product_missing_gwp_total
            - err_elementary_deactivated
            - err_product_missing_supplier
            - err_epd_unusable
            - err_epd_service
            - err_lca_update_not_queued
            - err_not_ready_for_epd
            - err_material_not_hazardous
            - err_material_no_limited_lifetime
            - err_invalid_lifetime_years
            - err_invalid_secondary_percentage_range
            - err_secondary_percentage_not_customizable
            - err_moisture_content_not_bio_based
            - err_invalid_moisture_content_range
            - err_declaration_not_exists
            - err_declaration_not_under_review
            - err_no_manufacturer
            - err_wrong_email_domain
            - err_user_exists
            - err_inviter_email_not_found
            - err_composite_used_in_supplier_products
            - err_composite_name_exists
            - err_plant_io_invalid_field
            - err_plant_io_field_not_switchable
            - err_plant_io_value_not_scoped
            - err_field_is_plant_level
            - err_negative_io_value
            - err_plant_io_mixed_allocation_groups
            - err_inies_sworn_statement_exists
            - err_supplier_in_use
            - err_supplier_name_exists
            - err_supplier_plant_in_use
            - err_supplier_plant_name_exists
            - err_supplier_product_in_recipe
            - err_supplier_product_in_silo
            - err_supplier_product_missing_supplier_plant
            - err_silo_in_use
            - err_silo_name_exists
            - err_elementary_unknown_matching
            - err_product_document_not_deletable
            - err_product_has_declarations
            - err_product_instance_in_recipe
            - err_prechain_product_in_recipe
            - err_prechain_product_exists
            - err_ccf_exists
            - err_ccf_not_completed
            - err_external_id_exists
            - err_bulk_upload_invalid_file
            - err_material_type_not_found
            - err_material_type_not_configured
            - err_unit_not_allowed_for_material
            - err_production_process_not_found
            - err_multiple_production_processes
            - err_process_plant_mismatch
            - err_material_process_incompatible
            - err_composite_not_allowed_in_recipe
            - err_elementary_not_allowed_in_recipe
            - err_prechain_circular_reference
            - err_product_type_no_recipe
            - err_product_mass_not_set
            - err_required_cell_empty
            - err_plant_not_found
            - err_plant_no_access
            - err_multiple_plants
            - err_product_already_exists
            - err_multiple_products
            - err_linked_product_type_mismatch
            - err_tech_spec_not_recognized
            - err_recipe_incomplete
            - err_orphan_row
            - err_duplicate_tech_spec
            - err_empty_sheet
            - err_no_products
            - err_tech_spec_invalid_value
            - err_dtp_service
            - err_data_translation_wrong_step
            - err_data_translation_invalid_plant_mapping
            - err_data_translation_unresolved_reference
            - err_data_translation_incomplete
            - err_data_translation_material_not_available
            - err_recycled_content_proof_missing
            - err_ppwr_declaration_exists
            - err_ppwr_declaration_editable_exists
            - err_ppwr_declaration_frozen
            - err_ppwr_doc_number_unavailable
            - err_ppwr_variant_mass_invalid
            - err_ppwr_variant_dimension_invalid
            - err_ppwr_variant_material_repeated
            - err_ppwr_variant_material_type
            - err_ppwr_invalid_field_key
            - err_ppwr_supplier_request_not_packaging_manufacturer
            - err_ppwr_supplier_request_pending
            - err_ppwr_supplier_request_not_pending
            - err_ppwr_field_not_requested
            - err_ppwr_document_limit_reached
            - err_ppwr_generation_not_packaging_manufacturer
            - err_ppwr_declaration_incomplete
            - err_ppwr_invalid_signatory
            - err_ppwr_invitation_send_failed
            - err_ppwr_supplier_link_placeholder_missing
            - err_ppwr_supplier_subject_missing
            - err_ppwr_supplier_email_missing
            - err_ppwr_verification_code_limit
            - err_ppwr_verification_code_send_failed
            - err_ppwr_email_not_verified
            - err_ppwr_attestation_required
            - err_ppwr_document_not_deletable
            - err_proof_document_limit
            - err_proof_size_limit
            - err_transport_route_unavailable
            - err_transport_missing_coordinates
            - err_transport_no_route
            - err_transport_same_address
            - err_reauthentication_required
            - err_two_factor_required
    EmidatMaterialType:
      type: object
      description: A material type backed by an Emidat elementary (material type).
      required:
        - category
        - elementary_id
      properties:
        category:
          type: string
          const: emidat-elementary
        elementary_id:
          type: string
          format: uuid
          description: >-
            Emidat material-type UUID. Your middleware maps your material code
            to this.
    CompositeMaterialTypeRef:
      type: object
      description: A material type backed by a composite you defined.
      required:
        - category
        - composite_id
      properties:
        category:
          type: string
          const: custom-composite
        composite_id:
          type: string
          format: uuid
          description: |
            UUID of the composite. Create via `POST /v2/composites`, or resolve
            your code with `GET /v2/composites?external_id=…`.
    TransportRouteInput:
      type: object
      description: >
        Transport distances to your gate, one per modality in km. Set at least
        one.
      properties:
        truck_distance_km:
          anyOf:
            - type: number
            - type: 'null'
          description: Distance by truck in km.
          example: 80
        train_distance_km:
          anyOf:
            - type: number
            - type: 'null'
          description: Distance by train in km.
        ship_distance_km:
          anyOf:
            - type: number
            - type: 'null'
          description: Distance by ship in km.
    TransportRoute:
      type: object
      description: |
        Transport distances to the consuming gate, one per modality in km. The
        route has no identity of its own — it is replaced through its parent.
      required:
        - truck_distance_km
        - train_distance_km
        - ship_distance_km
      properties:
        truck_distance_km:
          anyOf:
            - type: number
            - type: 'null'
          description: Distance by truck in km.
        train_distance_km:
          anyOf:
            - type: number
            - type: 'null'
          description: Distance by train in km.
        ship_distance_km:
          anyOf:
            - type: number
            - type: 'null'
          description: Distance by ship in km.
    Indicator:
      type: object
      required:
        - indicator_name
        - unit
        - value
      properties:
        indicator_name:
          type: string
          example: GWP-total
        unit:
          type: string
          example: kg CO2-Eq
        value:
          anyOf:
            - type: number
            - type: 'null'
          description: Null when the indicator could not be characterized.
          example: -1.7838794215158404
    SecondaryDataset:
      type: object
      description: >-
        A background (secondary) dataset contributing to the supplier product's
        impacts.
      required:
        - name
        - name_extra
        - source_url
        - database
        - geography
        - base_unit
      properties:
        name:
          type: string
        name_extra:
          anyOf:
            - type: string
            - type: 'null'
        source_url:
          type: string
        database:
          type: string
          description: >-
            Background database identifier, e.g. `ecoinvent-3.10` or
            `eurobitume`.
        geography:
          type: string
        base_unit:
          type: string
  responses:
    Unauthorized:
      description: >
        No credentials; or the key is malformed, unknown, revoked, or expired.
        The

        response is uniform and does not reveal which check failed.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
    Forbidden:
      description: >
        A valid key lacked the required permission, or targeted a resource
        outside

        its access.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
    InternalServerError:
      description: An unexpected server error occurred. Surface it to an operator.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
    BadGateway:
      description: A transient upstream dependency failed. Retry with backoff.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
  securitySchemes:
    ApiKeyAuth:
      type: apiKey
      in: header
      name: X-API-Key
      description: |
        Per-manufacturer API key in the `X-API-Key` header, format
        `emidat-{key_id}-{secret}` where `key_id` is a random public handle.
        Issued by an owner in the Emidat
        dashboard; carries its own permission scopes, optional plant
        restrictions, and optional expiry. A revoked, expired, or unknown key
        returns 401. See the Authentication guide for details.

````