> ## Documentation Index
> Fetch the complete documentation index at: https://api-doc.xmenu.it/llms.txt
> Use this file to discover all available pages before exploring further.

# Import menu

> Import or update your menu structure including categories, products, and options.

<Badge color="blue" icon="key">`write:menu`</Badge>

<Note>
  Each entity includes the `ext_id` field, which must be populated with its own unique identifier.

  If an element of the same entity with this `ext_id` does not already exist, a new one will be created. If the element exists, its content will be updated.

  The uniqueness scope of this ID is internal to the environment defined by the Client ID (`X-Client-Id`), meaning the same `ext_id` imported from different Client IDs will generate distinct elements.

  The `ext_id` values for `options` and `option_values` can be unique in that environment or only within their respective parent element (category/product for `options`, option for `option_values`).
</Note>


## OpenAPI

````yaml openapi-en.json POST /menu/import
openapi: 3.1.0
info:
  title: xMenu API
  description: xMenu Public API - REST endpoints and webhook notifications
  version: 1.0.0
servers:
  - url: https://app.xmenu.it/api
    description: xMenu API Production
security: []
paths:
  /menu/import:
    post:
      tags:
        - Menu Import
      summary: Import menu
      description: >-
        Import or update your menu structure including categories, products,
        options, and pricing using the external ID system. The system uses
        external IDs (ext_id) to identify entities. When importing, if an
        element with a matching ext_id exists, it updates; otherwise, it creates
        a new one. ID uniqueness is scoped to the environment defined by the
        Client ID.
      operationId: menuImport
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/MenuImportRequest'
      responses:
        '200':
          description: Menu import response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/MenuImportResponse'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
      security:
        - clientId: []
          clientSecret: []
        - oauth2: []
components:
  schemas:
    MenuImportRequest:
      type: object
      required:
        - pos_uid
        - update_mode
      properties:
        pos_uid:
          type: string
          description: Point-of-sale identifier
        update_mode:
          type: string
          enum:
            - replace
            - merge
          description: |-
            Update mode:
            - `replace` = Full replacement
            - `merge` = Append new items
        categories:
          type: array
          items:
            $ref: '#/components/schemas/ImportCategory'
          description: Array of categories. Required if update_mode = replace
        products:
          type: array
          items:
            $ref: '#/components/schemas/ImportProduct'
          description: Array of products. Required if update_mode = replace
    MenuImportResponse:
      type: object
      required:
        - success
      properties:
        success:
          type: boolean
          description: 'Operation result: `true` if successful, `false` if failed'
        error:
          type: string
          description: >-
            Error code if the operation failed. Possible values:

            - `IMPORT_ERROR` = Error during import (consult message parameter
            for details)


            See [Error codes](/docs/en/overview/error-codes) for general error
            codes that may also occur.
        message:
          type: string
          description: Error description if the import failed
    ImportCategory:
      type: object
      required:
        - ext_id
      properties:
        ext_id:
          type: string
          description: Unique external identifier
        name:
          type: string
          description: Category name. Required only when creating a new element
        description:
          type: string
          description: Category description
        image:
          type: string
          description: Image URL
        hidden:
          type: boolean
          description: |-
            Visibility status:
            - `false` = Visible
            - `true` = Archived
        position:
          type: integer
          description: Display order (starts at 1)
        options:
          type: array
          items:
            $ref: '#/components/schemas/ImportOption'
          description: Category-level options
    ImportProduct:
      type: object
      required:
        - ext_id
      properties:
        ext_id:
          type: string
          description: Unique external identifier
        category_ext_id:
          type: string
          description: >-
            Parent category external reference. Required only when creating a
            new element
        name:
          type: string
          description: Product name. Required only when creating a new element
        description:
          type: string
          description: Product description
        price:
          type: number
          description: Base price
        prices_table:
          type: object
          description: |-
            Location/method-specific pricing table with the following structure:
            ```javascript
            {
               "": { // all locations
                  "0": price0, // pickup at restaurant
                  "1": price1, // home delivery
                  ... // prices for other delivery methods
               },
               "subrestaurantUid1": { // Location 1
                  "0": price0,
                  "1": price1,
                  ...
               },
               ...
            }
            ```

            **Delivery method codes:**
            - `"0"` = Pickup at restaurant
            - `"1"` = Home delivery
            - `"0t"` = Table ordering
            - `"0mt"` = Digital menu
            - `"20"` = Pickup at delivery point
            - `"0e-{id}"` = Event
            - `"dcf-{id}"` = Custom delivery method
          additionalProperties:
            type: object
            additionalProperties:
              type: number
        image:
          type: string
          description: Image URL
        allergens:
          type: array
          items:
            type: string
          description: |-
            List of allergens. Possible values:
            - `gluten` = 1 - Gluten
            - `crustaceans` = 2 - Crustaceans
            - `eggs` = 3 - Eggs
            - `fish` = 4 - Fish
            - `peanuts` = 5 - Peanuts
            - `soya` = 6 - Soy
            - `milk` = 7 - Milk
            - `nuts` = 8 - Tree nuts
            - `celery` = 9 - Celery
            - `mustard` = 10 - Mustard
            - `sesame` = 11 - Sesame
            - `sulphites` = 12 - Sulphites
            - `lupin` = 13 - Lupin
            - `molluscs` = 14 - Molluscs
            - `freezer` = Frozen and deep-frozen
        symbols:
          type: array
          items:
            type: string
          description: |-
            List of symbols. Possible values:
            - `new` = New
            - `bestseller` = Best seller
            - `vegan` = Vegan
            - `vegetarian` = Vegetarian
            - `spicy` = Spicy
            - `pizza` = Pizza
            - `burger` = Burger
            - `chips` = Chips
            - `icecream` = Ice cream
            - `sweets` = Desserts
            - `drink` = Drink
            - `freshfish` = Fresh fish
            - `cookedfish` = Cooked fish
        suggested:
          type: boolean
          description: >-
            Whether the product is marked as recommended (displays the 'Best
            choice' badge and highlights the product in the menu)
        price_sale_alert:
          type: boolean
          description: >-
            Whether the product is featured (displayed prominently when the user
            starts composing the cart)
        price_sale_badge:
          type: integer
          description: >-
            Promotional text badge shown on the product detail page when
            `price_sale_alert` is `true`. Possible values:

            - `0` = On Sale

            - `1` = Promo of the Day

            - `2` = How often do you get this chance?

            - `3` = But why miss it?

            - `4` = When will you get a chance like this again?

            - `5` = Promo of the Week

            - `6` = Promo of the Month

            - `7` = Unbelievable!

            - `8` = Black Friday special

            - `9` = Have you already tried it?
        checkout_selling:
          type: boolean
          description: Whether the product is proposed at checkout as cross-selling
        hidden:
          type: boolean
          description: |-
            Visibility status:
            - `false` = Visible
            - `true` = Archived
        position:
          type: integer
          description: Display order
        inherits_options:
          type: string
          enum:
            - sync
            - 'yes'
            - none
          description: >-
            Option inheritance from category:

            - `yes` = Full inheritance — product shows only the category
            options; product-specific options are ignored

            - `sync` = Partial inheritance — product shows both the category
            options and its own product-specific options

            - `none` = No inheritance — product shows only its own specific
            options
        options:
          type: array
          items:
            $ref: '#/components/schemas/ImportOption'
          description: Product-specific options
    ImportOption:
      type: object
      required:
        - ext_id
      properties:
        ext_id:
          type: string
          description: Unique external identifier
        name:
          type: string
          description: Option title. Required only when creating a new element
        short_name:
          type: string
          description: Brief title
        type:
          type: string
          enum:
            - single
            - multiple
          description: |-
            Selection type:
            - `single` = Single choice
            - `multiple` = Multiple choices allowed
        min_selectable:
          type: integer
          description: Minimum selections (for type `multiple`)
        max_selectable:
          type: integer
          description: Maximum selections (for type `multiple`)
        max_quantity:
          type: integer
          description: Maximum quantity per value
        note:
          type: string
          description: Notes
        hidden:
          type: boolean
          description: |-
            Visibility status:
            - `false` = Visible
            - `true` = Archived
        position:
          type: integer
          description: Display order
        primary:
          type: boolean
          description: |-
            Primary option flag (only for type `single`):
            - `false` = Non-primary
            - `true` = Primary option
        first_default:
          type: boolean
          description: |-
            Default selection behavior (only for type `single`):
            - `false` = User must select
            - `true` = First value used as default
        show_caption:
          type: boolean
          description: |-
            Cart display setting (only for type `single`):
            - `false` = Hide in cart
            - `true` = Display in cart
        print_caption:
          type: boolean
          description: |-
            Print behavior:
            - `false` = Omit from order printing
            - `true` = Include in printing
        option_values:
          type: array
          items:
            $ref: '#/components/schemas/ImportOptionValue'
          description: Array of option values
    ImportOptionValue:
      type: object
      required:
        - ext_id
      properties:
        ext_id:
          type: string
          description: Unique external identifier
        name:
          type: string
          description: Value name. Required only when creating a new element
        short_name:
          type: string
          description: Brief name
        price_operator:
          type: string
          enum:
            - +
            - '-'
            - '*'
            - /
          description: |-
            Price modification operator:
            - `+` = Addition
            - `-` = Subtraction
            - `*` = Multiplication
            - `/` = Division
        price_operand:
          type: number
          description: Price modification amount
        hidden:
          type: boolean
          description: |-
            Visibility status:
            - `false` = Visible
            - `true` = Archived
        checked_default:
          type: boolean
          description: |-
            Pre-selected flag:
            - `false` = Not preselected
            - `true` = Preselected by default
        position:
          type: integer
          description: Display order
        restrict_to_primary_value_uids:
          type: array
          items:
            type: string
          nullable: true
          description: >-
            UIDs of primary option values for which this value is available:

            - `null` = No restriction (always available)

            - `[]` = Restriction active, but no primary values allowed (never
            available)

            - `["uid1", ...]` = Available only when one of these primary option
            values is selected


            The referenced UIDs must belong to the primary option within the
            same product or category.
  responses:
    Unauthorized:
      description: Authentication failed.
      content:
        application/json:
          schema:
            oneOf:
              - type: object
                description: >-
                  Standard error format (when using API Key or Client ID/Secret
                  authentication)
                required:
                  - success
                  - error
                properties:
                  success:
                    type: boolean
                    enum:
                      - false
                    description: Always false for errors
                  error:
                    type: string
                    enum:
                      - RESTAURANT_NOT_FOUND
                      - INVALID_KEY
                      - INVALID_AUTH
                    description: Error code
                  message:
                    type: string
                    description: Human-readable error description
              - type: object
                description: OAuth error format (when using Bearer token authentication)
                required:
                  - error
                properties:
                  error:
                    type: string
                    enum:
                      - invalid_token
                      - invalid_request
                    description: OAuth error code (RFC 6749)
                  error_description:
                    type: string
                    description: Human-readable error description
          examples:
            standard:
              summary: Standard error format (API Key / Client ID+Secret)
              value:
                success: false
                error: INVALID_KEY
                message: The provided API key is not valid
            oauth:
              summary: OAuth error format (Bearer token)
              value:
                error: invalid_token
                error_description: Access token is invalid or expired
    Forbidden:
      description: Authorization failed - insufficient permissions or access denied.
      content:
        application/json:
          schema:
            oneOf:
              - type: object
                description: >-
                  Standard error format (when using API Key or Client ID/Secret
                  authentication)
                required:
                  - success
                  - error
                properties:
                  success:
                    type: boolean
                    enum:
                      - false
                    description: Always false for errors
                  error:
                    type: string
                    enum:
                      - API_DISABLED
                      - INSUFFICIENT_SCOPE
                      - UNAUTHORIZED
                    description: Error code
                  message:
                    type: string
                    description: Human-readable error description
              - type: object
                description: OAuth error format (when using Bearer token authentication)
                required:
                  - error
                properties:
                  error:
                    type: string
                    enum:
                      - insufficient_scope
                      - invalid_request
                    description: OAuth error code (RFC 6749)
                  error_description:
                    type: string
                    description: Human-readable error description
          examples:
            standard:
              summary: Standard error format (API Key / Client ID+Secret)
              value:
                success: false
                error: API_DISABLED
                message: API access is not enabled for the restaurant
            oauth:
              summary: OAuth error format (Bearer token)
              value:
                error: insufficient_scope
                error_description: 'Missing required permissions: write:orders'
  securitySchemes:
    clientId:
      type: apiKey
      in: header
      name: X-Client-Id
      description: >-
        Client ID for API Client authentication (must be used together with
        Client Secret)
    clientSecret:
      type: apiKey
      in: header
      name: X-Client-Secret
      description: >-
        Client Secret for API Client authentication (must be used together with
        Client ID)
    oauth2:
      type: oauth2
      flows:
        clientCredentials:
          tokenUrl: https://app.xmenu.it/oauth/token
          scopes: {}
      description: >-
        OAuth 2.0 authentication using client credentials flow. The access token
        must be included in the Authorization header as a Bearer token.

````