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

# Create and update categories

> Create or update categories in bulk. If a category with the same name already exists, it is updated.

You can create or update categories in bulk by name. If a category with the same name already exists in the same store and branch, it is updated; otherwise, it is created.

<ParamField path="app_id" type="string" required>
  Your store ID in Jelou Shop.
</ParamField>

<ParamField body="resources" type="object[]" required>
  List of categories to create or update (max. 500 per request).

  <Expandable title="Category fields">
    <ParamField body="name" type="string" required>
      Category name (max. 255 characters). Used as a unique identifier within the store and branch.
    </ParamField>

    <ParamField body="description" type="string">
      Category description.
    </ParamField>

    <ParamField body="image" type="string">
      **Public** URL of the category image. Private/internal URLs are not accepted.
    </ParamField>

    <ParamField body="order" type="integer" default="0">
      Category sort position (min. 0, max. 999999). When greater than 0, it must be unique within the same level (app + parent category + branch). The value `0` is treated as "unordered".
    </ParamField>

    <ParamField body="status" type="boolean" default="true">
      Category status (active/inactive).
    </ParamField>

    <ParamField body="branch" type="string">
      Branch code to which the category belongs. The branch must already exist.
    </ParamField>

    <ParamField body="parent_id" type="integer">
      Parent category ID (for hierarchy). Must already exist in the same store.
    </ParamField>
  </Expandable>
</ParamField>

<Warning>
  The branch must be created before assigning it to a category. Use the [Create branches](/en/guides/integraciones/e-commerce/api-sucursales/crear) endpoint to register it first.
</Warning>

<RequestExample>
  ```bash cURL theme={null}
  curl -X POST "https://gateway.jelou.ai/ecommerce/v2/apps/{app_id}/batch/categories/upsert" \
    -H "x-api-key: YOUR_API_KEY" \
    -H "Content-Type: application/json" \
    -d '{
      "resources": [
        {
          "name": "Pizzas",
          "description": "All our artisan pizzas",
          "image": "https://example.com/images/pizzas.jpg",
          "order": 1,
          "status": true,
          "branch": "BRANCH-DOWNTOWN"
        },
        {
          "name": "Beverages",
          "description": "Hot and cold beverages",
          "order": 2,
          "branch": "BRANCH-DOWNTOWN"
        },
        {
          "name": "Desserts",
          "order": 3
        }
      ]
    }'
  ```
</RequestExample>

<ResponseExample>
  ```json 202 Accepted theme={null}
  {
    "message": "Batch upsert process initiated successfully",
    "count": 3,
    "jobs": 1
  }
  ```

  ```json 422 Validation Error theme={null}
  {
    "message": "Each category must have a name.",
    "errors": {
      "resources.0.name": ["Each category must have a name."]
    }
  }
  ```
</ResponseExample>

## Behavior

<AccordionGroup>
  <Accordion title="Asynchronous processing">
    The endpoint returns `202 Accepted` immediately. Categories are processed in the background.
  </Accordion>

  <Accordion title="Upsert by name">
    Categories are identified by their `name` within the same store and branch. If one with that name already exists, it is updated instead of creating a new one.
  </Accordion>

  <Accordion title="Non-existent branch">
    If the branch code does not match any branch in the store, the category is created without an assigned branch.
  </Accordion>

  <Accordion title="Images">
    If an image URL is provided, it is downloaded and stored in the background after the category is created. The URL must be public; private/internal URLs are rejected.
  </Accordion>

  <Accordion title="Hierarchy (parent_id)">
    Use `parent_id` to nest categories. The parent must exist in the same store before the batch is processed. To build a new hierarchy, create the parent categories first, then send the children referencing their `parent_id`.
  </Accordion>

  <Accordion title="Unique order per level">
    When `order` is greater than 0, it must be unique within the same level (app + parent category + branch). If two categories in the same batch share an `order` at the same level, or it clashes with an existing category, the request fails with `422`. An `order` of 0 or null is treated as "unordered" and skips the uniqueness check.
  </Accordion>
</AccordionGroup>

## Validation errors

<Accordion title="Common error messages">
  | Field                   | Message                                                                                                                    |
  | ----------------------- | -------------------------------------------------------------------------------------------------------------------------- |
  | `resources`             | The resources field is required.                                                                                           |
  | `resources`             | At least one category is required.                                                                                         |
  | `resources`             | Cannot process more than 500 categories at once.                                                                           |
  | `resources.*.name`      | Each category must have a name.                                                                                            |
  | `resources.*.image`     | Category image must be a valid URL.                                                                                        |
  | `resources.*.order`     | Category order must be an integer. / Category order cannot be negative. / Category order cannot exceed 999999.             |
  | `resources.*.order`     | Order {n} is duplicated within this batch for the same parent/branch. / Order {n} is already assigned to another category. |
  | `resources.*.status`    | Category status must be a boolean.                                                                                         |
  | `resources.*.parent_id` | Parent category id must be an integer. / The parent category does not exist for this app.                                  |
  | `resources`             | This app already has {n} categories. Adding {m} new categories would exceed the limit of {limit}.                          |
</Accordion>

## Limits

* Maximum **500 categories** per request.
* Total categories **per store** limit (configurable; defaults to **500**). If the batch exceeds the remaining limit, the request fails with `422`.
* All categories are validated before processing.

<Note>
  Replace `{app_id}` with your store ID and `YOUR_API_KEY` with your [API key](/en/guides/configuracion/claves-api).
</Note>
