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

# Granular catalog updates

> Create, update, and delete individual catalog resources with targeted requests.

Granular endpoints are designed for low-latency changes between complete snapshots. They look up one caller-owned ID inside its parent scope and write only the affected rows. They do not rebuild or compare the complete catalog.

## Create a product

Creation endpoints require `Idempotency-Key`.

```bash theme={null}
curl https://server.chataigne.ai/v1/locations/loc_r8v4n2c6tz/catalogs/delivery-menu/products \
  -X POST \
  -H "x-api-key: $CHATAIGNE_API_KEY" \
  -H "Idempotency-Key: create-burger-veggie" \
  -H "Content-Type: application/json" \
  -d '{
    "id": "burger-veggie",
    "name": "Veggie Burger",
    "category_id": "burgers",
    "price": {"amount":11.9,"currency":"EUR"},
    "modifier_group_ids": ["sauces"],
    "disabled": false,
    "out_of_stock": false,
    "restrictions": [],
    "price_overrides": [],
    "bundle_only": false
  }'
```

The returned product exposes its price directly. There is no SKU field.

## Update one product

`PATCH` uses merge semantics. Omitted fields remain unchanged. Explicit `null` clears nullable fields such as `description` and `image_url`. Supplying `modifier_group_ids` replaces that product's complete group relationship list. Supplying `restrictions: []` or `price_overrides: []` clears those rules.

```bash theme={null}
curl https://server.chataigne.ai/v1/locations/loc_r8v4n2c6tz/catalogs/delivery-menu/products/burger-veggie \
  -X PATCH \
  -H "x-api-key: $CHATAIGNE_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "price":{"amount":12.4,"currency":"EUR"},
    "out_of_stock":true
  }'
```

## Categories

Use `/categories` to list and create categories, then `/categories/{category_id}` to retrieve, patch, or delete one category. A category still containing products or bundles cannot be deleted and returns `409 catalog_resource_in_use`.

## Modifier groups and modifiers

Groups live under `/modifier_groups`. Individual modifiers live under `/modifier_groups/{modifier_group_id}/modifiers`, which means the same modifier ID may be reused in another group.

```bash theme={null}
curl https://server.chataigne.ai/v1/locations/loc_r8v4n2c6tz/catalogs/delivery-menu/modifier_groups/sauces/modifiers \
  -X POST \
  -H "x-api-key: $CHATAIGNE_API_KEY" \
  -H "Idempotency-Key: create-hot-sauce" \
  -H "Content-Type: application/json" \
  -d '{"id":"hot-sauce","name":"Hot sauce","price":{"amount":0.5,"currency":"EUR"}}'
```

Modifiers support the same `disabled`, `out_of_stock`, `restrictions`, and `price_overrides` fields as products. A modifier group attached to a product cannot be deleted until the relationship is removed from that product.

## Bundles

Bundles reference public `product_ids`, never SKUs. When `lines` is present in a bundle PATCH, it atomically replaces only that bundle's lines.

```json theme={null}
{
  "id": "classic-meal",
  "name": "Classic Meal",
  "category_id": "meals",
  "price": { "amount": 16.9, "currency": "EUR" },
  "disabled": false,
  "out_of_stock": false,
  "restrictions": [],
  "price_overrides": [],
  "lines": [
    {
      "id": "main",
      "name": "Choose your burger",
      "min_selections": 1,
      "max_selections": 1,
      "product_ids": ["burger-classic", "burger-veggie"]
    }
  ]
}
```

Bundles support the same `disabled`, `out_of_stock`, `restrictions`, and `price_overrides` fields. Products referenced by bundle lines cannot be deleted until those references are removed.

## Pagination and errors

Collection endpoints accept `limit`, `starting_after`, and `ending_before` and return the standard `{ "object": "list", "data": [], "has_more": false, "url": "…" }` envelope. See [Pagination](/concepts/pagination), [Errors](/concepts/errors), and [Idempotency](/concepts/idempotency).
