Categories organize products into a hierarchy (e.g. "Clothing > Shirts > T-Shirts"). Each product can belong to one category.

## List Categories

```
GET /api/v1/categories
```

### Query Parameters

| Parameter | Type | Default | Description |
|-----------|------|---------|-------------|
| `limit` | `number` | 10 | Categories per page (1-100) |
| `offset` | `number` | 0 | Categories to skip |
| `query` | `string` | – | Search by category name |
| `active` | `boolean` | – | Filter by active status |
| `lang` | `string` | – | Locale code for translations (e.g. `pl-PL`) |

### Response

```json
{
  "data": [
    {
      "id": "0191abc0-1234-7def-8000-000000000001",
      "name": "Shirts",
      "slug": "shirts",
      "image": "https://cdn.example.com/shirts.jpg",
      "active": true,
      "parentId": null,
      "translations": []
    }
  ],
  "meta": {
    "count": 5
  }
}
```

---

## Get Category

```
GET /api/v1/categories/:idOrSlug
```

Returns a single category by UUID or slug, with associated products and translations. Supports `?lang=` for translated content.

---

## Create Category

```
POST /api/v1/categories
```

Slug is auto-generated from the name if not provided. Image URLs are downloaded and re-uploaded to the store's CDN. Supports nested categories via `parentId`.

### Request Body

| Field | Type | Required | Description |
|-------|------|----------|-------------|
| `name` | `string` | Yes | Category display name |
| `slug` | `string` | No | URL slug (auto-generated from name) |
| `description` | `string` | No | Plain text description |
| `image` | `string` | No | Category image URL |
| `parentId` | `string` | No | Parent category UUID for nesting |
| `active` | `boolean` | No | Visible on storefront (default: `true`) |

```bash
# Top-level category
curl -X POST \
  -H "Authorization: Bearer your_api_key" \
  -H "Content-Type: application/json" \
  -d '{"name": "Clothing"}' \
  https://your-store.yns.store/api/v1/categories

# Nested category
curl -X POST \
  -H "Authorization: Bearer your_api_key" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "T-Shirts",
    "parentId": "0191abc0-1234-7def-8000-000000000001"
  }' \
  https://your-store.yns.store/api/v1/categories
```

---

## Update Category

```
PATCH /api/v1/categories/:idOrSlug
```

Partially updates a category. Only the provided fields are changed.

### Request Body

| Field | Type | Description |
|-------|------|-------------|
| `name` | `string` | New category name |
| `slug` | `string` | New URL slug |
| `description` | `string \| null` | Description (`null` to clear) |
| `image` | `string \| null` | Image URL (`null` to clear) |
| `parentId` | `string \| null` | Parent category UUID (`null` for top-level) |
| `active` | `boolean` | Visibility on storefront |

---

## Delete Category

```
DELETE /api/v1/categories/:idOrSlug
```

Accepts a UUID or a slug.

### Response

```json
{
  "ok": true,
  "deleted": 1
}
```

### Errors

| Status | Meaning |
|--------|---------|
| `404` | No category matches the identifier |
| `409` | The category is still referenced by products or subcategories |

Reassign or delete the dependent products and subcategories first, then retry.

```bash
curl -X DELETE \
  -H "Authorization: Bearer your_api_key" \
  https://your-store.yns.store/api/v1/categories/candles
```

---

## Translations

```
PUT /api/v1/categories/:idOrSlug/translations/:locale
```

Upsert or delete a single locale's translated fields for a category. See the [Localization page](/docs/api-reference/localization#writing-translations) for the full field reference, behaviour, and examples.