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

# Update Product Component

> Updates your nutrition for a product component. Only the fields you supply are
changed.

The component's `name` cannot be changed — the name row is shared with every
other account that registered the same ingredient. Use `clear` to reset a value
to "not supplied"; omitting a field means "leave unchanged", so omission cannot
express erasure.



## OpenAPI

````yaml /openapi.json patch /v1/product_components/{id}
openapi: 3.1.0
info:
  title: Flex API
  description: >-
    The Flex API powers HSA/FSA payment processing for healthcare commerce:
    checkout sessions, payment intents, subscriptions, customers, refunds,
    disputes, and eligibility. Authenticate with your partner API key as a
    Bearer token. All endpoints are scoped to your partner account, and test
    mode is fully supported via test API keys.
  version: 0.1.0
servers:
  - url: https://api.withflex.com
security:
  - BearerAuth: []
tags:
  - name: Balance Transactions
  - name: Captures
  - name: Checkout Sessions
  - name: Coupons
  - name: Customers
  - name: Disputes
  - name: Events
  - name: Exports
  - name: Files
  - name: Invoices
  - name: Letters
  - name: Orders
  - name: Payment Intents
  - name: Payment Links
  - name: Payouts
  - name: Prices
  - name: Products
  - name: Promo Codes
  - name: Receipts
  - name: Refunds
  - name: Setup Intents
  - name: Shipping Rates
  - name: Subscriptions
paths:
  /v1/product_components/{id}:
    patch:
      tags:
        - Products
      summary: Update Product Component
      description: >-
        Updates your nutrition for a product component. Only the fields you
        supply are

        changed.


        The component's `name` cannot be changed — the name row is shared with
        every

        other account that registered the same ingredient. Use `clear` to reset
        a value

        to "not supplied"; omitting a field means "leave unchanged", so omission
        cannot

        express erasure.
      operationId: v1.product_components.update
      parameters:
        - in: path
          name: id
          description: The component's `fcomp_` identifier.
          required: true
          schema:
            description: The component's `fcomp_` identifier.
            examples:
              - fcomp_01J9XR8M3K7VZ8N2YB4WJ6T0RA
            type: string
          style: simple
          example: fcomp_01J9XR8M3K7VZ8N2YB4WJ6T0RA
      requestBody:
        description: An envelope wrapping a single product component object.
        content:
          application/json:
            schema:
              $ref: >-
                #/components/schemas/ProductComponentBody_for_UpdateProductComponentRequest
            example:
              product_component:
                category: base
                nutrition_basis: per_100g
                nutrition: {}
        required: true
      responses:
        '200':
          description: An envelope wrapping a single product component object.
          content:
            application/json:
              schema:
                $ref: >-
                  #/components/schemas/ProductComponentBody_for_V1ProductComponent
              example:
                product_component:
                  component_id: fcomp_01J9XR8M3K7VZ8N2YB4WJ6T0RA
                  component_nutrition_id: fcn_01J9XR8M3K7VZ8N2YB4WJ6T0RA
                  name: string
                  shared: true
                  test_mode: true
                  category: string
                  nutrition: {}
                  vegan: true
                  gluten_free: true
                  created_at: string
                  updated_at: string
        '401':
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HttpErrorOut'
              example:
                code: string
                detail: string
        '403':
          description: Forbidden
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HttpErrorOut'
              example:
                code: string
                detail: string
        '404':
          description: Not Found
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HttpErrorOut'
              example:
                code: string
                detail: string
        '409':
          description: Conflict
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HttpErrorOut'
              example:
                code: string
                detail: string
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
              example:
                detail:
                  - loc:
                      - string
                    msg: string
                    type: string
        '429':
          description: Too Many Requests
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HttpErrorOut'
              example:
                code: string
                detail: string
      security:
        - BearerAuth:
            - products:write
components:
  schemas:
    ProductComponentBody_for_UpdateProductComponentRequest:
      description: An envelope wrapping a single product component object.
      type: object
      required:
        - product_component
      properties:
        product_component:
          $ref: '#/components/schemas/UpdateProductComponentRequest'
          description: The product component object.
      example:
        product_component:
          category: base
          nutrition_basis: per_100g
          nutrition: {}
    ProductComponentBody_for_V1ProductComponent:
      description: An envelope wrapping a single product component object.
      type: object
      required:
        - product_component
      properties:
        product_component:
          $ref: '#/components/schemas/V1ProductComponent'
          description: The product component object.
      example:
        product_component:
          component_id: fcomp_01J9XR8M3K7VZ8N2YB4WJ6T0RA
          component_nutrition_id: fcn_01J9XR8M3K7VZ8N2YB4WJ6T0RA
          name: string
          shared: true
          test_mode: true
          category: string
          nutrition: {}
          vegan: true
          gluten_free: true
          created_at: string
          updated_at: string
    HttpErrorOut:
      title: HttpError
      description: The error response returned when a request cannot be completed.
      type: object
      required:
        - code
        - detail
      properties:
        code:
          description: A short machine-readable error code identifying the type of error.
          type: string
        detail:
          description: A human-readable explanation of what went wrong.
          type: string
      example:
        code: string
        detail: string
    HTTPValidationError:
      description: The error response returned when request validation fails (HTTP 422).
      type: object
      required:
        - detail
      properties:
        detail:
          description: The list of validation errors, one entry per invalid field.
          type: array
          items:
            $ref: '#/components/schemas/ValidationErrorItem'
      example:
        detail:
          - loc:
              - string
            msg: string
            type: string
    UpdateProductComponentRequest:
      description: >-
        Parameters for updating a product component. Only the fields you supply
        are changed; omitted fields are left unchanged.


        There is no `name`: the underlying name row is shared with every other
        partner that registered the same ingredient, so a rename here would edit
        their data. Register a new component instead.


        To reset a value to "not supplied", list it in `clear` — omitting it
        means "leave alone", so omission cannot express erasure. Clearing a
        field and setting it in the same request is rejected.
      type: object
      properties:
        category:
          description: The component's menu category.
          anyOf:
            - $ref: '#/components/schemas/ComponentCategory'
            - type: 'null'
        nutrition_basis:
          description: >-
            The basis the supplied `nutrition` values are expressed on. Defaults
            to `per_100g`. `as_served` converts by `serving_size_g` — the one in
            this request if present, otherwise the stored one.
          anyOf:
            - $ref: '#/components/schemas/NutritionBasis'
            - type: 'null'
        serving_size_g:
          description: The standard portion of this component, in grams.
          type:
            - number
            - 'null'
          format: double
        nutrition:
          description: Nutrient values to change. Omitted nutrients are left unchanged.
          anyOf:
            - $ref: '#/components/schemas/ComponentNutritionValues'
            - type: 'null'
        vegan:
          description: Whether the component is vegan.
          type:
            - boolean
            - 'null'
        gluten_free:
          description: Whether the component is gluten-free.
          type:
            - boolean
            - 'null'
        canonical_food_key:
          description: The join key into Flex's national price book.
          type:
            - string
            - 'null'
        clear:
          description: Fields to reset to "not supplied".
          type:
            - array
            - 'null'
          items:
            $ref: '#/components/schemas/ClearableField'
      example:
        category: base
        nutrition_basis: per_100g
        nutrition: {}
    V1ProductComponent:
      description: >-
        A component together with the nutrition this partner has recorded for
        it. Every nutrient value is per 100 g.
      type: object
      required:
        - category
        - component_id
        - component_nutrition_id
        - created_at
        - gluten_free
        - name
        - nutrition
        - shared
        - test_mode
        - vegan
      properties:
        component_id:
          description: >-
            The component's unique identifier. This is the id `component_items`
            on `PATCH /v1/products/{id}` accepts.
          type: string
          example: fcomp_01J9XR8M3K7VZ8N2YB4WJ6T0RA
        component_nutrition_id:
          description: >-
            The identifier of the nutrition record holding your figures for this
            component.
          type: string
          example: fcn_01J9XR8M3K7VZ8N2YB4WJ6T0RA
        name:
          description: The component's name, normalized to lowercase.
          type: string
        shared:
          description: >-
            Whether the underlying name row is shared across partners rather
            than owned by you. `true` for everything registered through this
            endpoint today, which is why the name cannot be changed.
          type: boolean
        test_mode:
          description: Whether these figures belong to test mode.
          type: boolean
        category:
          description: The component's menu category.
          type: string
        serving_size_g:
          description: The standard portion, in grams. Not a per-100 g nutrient.
          type:
            - number
            - 'null'
          format: double
        nutrition:
          $ref: '#/components/schemas/ComponentNutritionValues'
          description: Nutrient values, per 100 g.
        vegan:
          description: Whether the component is vegan.
          type: boolean
        gluten_free:
          description: Whether the component is gluten-free.
          type: boolean
        canonical_food_key:
          description: >-
            The join key into Flex's national price book, or `null` if not yet
            mapped.
          type:
            - string
            - 'null'
        created_at:
          $ref: '#/components/schemas/Timestamptz'
          description: When these figures were first recorded.
        updated_at:
          description: When these figures were last changed, or `null` if never.
          anyOf:
            - $ref: '#/components/schemas/Timestamptz'
            - type: 'null'
      example:
        component_id: fcomp_01J9XR8M3K7VZ8N2YB4WJ6T0RA
        component_nutrition_id: fcn_01J9XR8M3K7VZ8N2YB4WJ6T0RA
        name: string
        shared: true
        test_mode: true
        category: string
        nutrition: {}
        vegan: true
        gluten_free: true
        created_at: string
        updated_at: string
    ValidationErrorItem:
      description: >-
        Validation errors have their own schema to provide context for invalid
        requests eg. mismatched types and out of bounds values. There may be any
        number of these per 422 UNPROCESSABLE ENTITY error.
      type: object
      required:
        - loc
        - msg
        - type
      properties:
        loc:
          description: >-
            The location as a [`Vec`] of [`String`]s -- often in the form
            `["body", "field_name"]`, `["query", "field_name"]`, etc. They may,
            however, be arbitarily deep.
          type: array
          items:
            type: string
        msg:
          description: The message accompanying the validation error item.
          type: string
        type:
          description: >-
            The type of error, often "type_error" or "value_error", but
            sometimes with more context like as "value_error.number.not_ge"
          type: string
      example:
        loc:
          - string
        msg: string
        type: string
    ComponentCategory:
      type: string
      enum:
        - base
        - protein
        - topping
        - premium
        - dressing
      x-ms-enum:
        name: ComponentCategory
        modelAsString: false
        values:
          - value: base
            name: Base
            description: The bowl's base — a grain, green or other foundation.
          - value: protein
            name: Protein
            description: A protein.
          - value: topping
            name: Topping
            description: A standard topping.
          - value: premium
            name: Premium
            description: A premium topping.
          - value: dressing
            name: Dressing
            description: >-
              A dressing. The one category the eligibility engine gates
              differently.
      description: >-
        A component's menu category.


        An enum on the way in and a plain string on the way out, deliberately.
        `product_component_nutrition.category` is `text` with no CHECK
        constraint (per the company convention that the backend owns
        validation), so a row written by a backfill or by raw SQL can hold a
        value outside this set. Being strict on write keeps bad values out;
        being tolerant on read means such a row is still retrievable instead of
        500ing on serialization.


        The variants mirror [`flex_core::product_metadata::VALID_CATEGORIES`],
        which is what the write path actually validates against;
        `test_component_category_matches_flex_core` pins the two together so a
        category added there cannot be silently unreachable through the API.


        - `base`: The bowl's base — a grain, green or other foundation.

        - `protein`: A protein.

        - `topping`: A standard topping.

        - `premium`: A premium topping.

        - `dressing`: A dressing. The one category the eligibility engine gates
        differently.
      example: base
    NutritionBasis:
      type: string
      enum:
        - per_100g
        - as_served
      x-ms-enum:
        name: NutritionBasis
        modelAsString: false
        values:
          - value: per_100g
            name: Per100g
            description: The values are already per 100 g. The default.
          - value: as_served
            name: AsServed
            description: >-
              The values describe one `serving_size_g` portion as served, and
              are converted to per 100 g before being stored.
      description: >-
        The basis the supplied nutrient values are expressed on.


        Storage is always per 100 g; this only describes the *request*.
        `as_served` requires a usable `serving_size_g` to convert by.


        - `per_100g`: The values are already per 100 g. The default.

        - `as_served`: The values describe one `serving_size_g` portion as
        served, and are converted to per 100 g before being stored.
      example: per_100g
    ComponentNutritionValues:
      description: >-
        Nutrient values for one component. **Every value is per 100 g of the
        component**, never per serving — see `nutrition_basis` on the write
        paths for how per-serving figures are converted on the way in.


        A `null` means *not supplied*, which is distinct from `0`: the
        eligibility engine treats a missing nutrient as a reason it cannot
        produce a split, whereas a zero is a real measurement.
      type: object
      properties:
        calories:
          description: Energy, kcal per 100 g.
          type:
            - number
            - 'null'
          format: double
        total_fat_g:
          description: >-
            Total fat, g per 100 g. Informational — the eligibility gate uses
            saturated fat.
          type:
            - number
            - 'null'
          format: double
        saturated_fat_g:
          description: >-
            Saturated fat, g per 100 g. This is the fat the eligibility gate
            uses.
          type:
            - number
            - 'null'
          format: double
        trans_fat_g:
          description: Trans fat, g per 100 g.
          type:
            - number
            - 'null'
          format: double
        carbohydrate_g:
          description: Carbohydrate, g per 100 g.
          type:
            - number
            - 'null'
          format: double
        fiber_g:
          description: Fiber, g per 100 g.
          type:
            - number
            - 'null'
          format: double
        protein_g:
          description: Protein, g per 100 g.
          type:
            - number
            - 'null'
          format: double
        sodium_mg:
          description: Sodium, mg per 100 g.
          type:
            - number
            - 'null'
          format: double
        added_sugar_g:
          description: Added sugar, g per 100 g.
          type:
            - number
            - 'null'
          format: double
      example: {}
    ClearableField:
      description: >-
        A nullable field an update may reset to "not supplied".


        `category`, `vegan` and `gluten_free` are absent on purpose: they are
        never null in storage, so they can be changed but not cleared.
      type: string
      enum:
        - serving_size_g
        - calories
        - total_fat_g
        - saturated_fat_g
        - trans_fat_g
        - carbohydrate_g
        - fiber_g
        - protein_g
        - sodium_mg
        - added_sugar_g
        - canonical_food_key
      example: serving_size_g
    Timestamptz:
      description: >-
        A timestamp encoded as an RFC 3339 / ISO 8601 string (e.g.
        `2026-06-15T14:30:00Z`).
      type: string
      example: string
  securitySchemes:
    BearerAuth:
      type: http
      scheme: bearer
      bearerFormat: API Key
      description: Use a Bearer token to access this API.

````