Skip to content

Categories

List Categories

GET /api/v1/categories

Required permission: categories:read

Query parameters

Parameter Type Default Description
page int 1 Page number
per_page int 20 Items per page
slug string Filter by slug (LIKE)

Response 200 OK

{
  "data": [
    {
      "created_at": "2026-02-23T15:17:42.320Z",
      "updated_at": "2026-02-23T15:17:42.320Z",
      "id": "uuid",
      "slug": "sport",
      "parent_id": null,
      "is_active": true,
      "order": 0,
      "created_by": "uuid",
      "translations": []
    }
  ],
  "pagination": {
    "total": 50,
    "page": 1,
    "per_page": 20,
    "pages": 3,
    "has_next": true,
    "has_prev": false
  }
}


Get Category Tree

Returns the full category hierarchy as a nested tree structure. Intended for frontend navigation — no authentication required.

GET /api/v1/categories/tree

Authentication: Not required

Response 200 OK

[
  {
    "id": "uuid",
    "slug": "sport",
    "is_active": true,
    "order": 0,
    "parent_id": null,
    "translations": [
      {
        "id": "uuid",
        "category_id": "uuid",
        "language_id": "uuid",
        "name": "Sport",
        "description": null,
        "created_at": "2026-01-01T00:00:00Z",
        "updated_at": null
      }
    ],
    "children": [
      {
        "id": "uuid",
        "slug": "football",
        "is_active": true,
        "order": 0,
        "parent_id": "uuid",
        "translations": [
          {
            "id": "uuid",
            "category_id": "uuid",
            "language_id": "uuid",
            "name": "Football",
            "description": null,
            "created_at": "2026-01-01T00:00:00Z",
            "updated_at": null
          }
        ],
        "children": []
      }
    ]
  }
]

Info

The tree is sorted by the order field at every level.


Create Category

POST /api/v1/categories

Required permission: categories:create

Request body

{
  "slug": "sport",
  "parent_id": null,
  "is_active": true,
  "order": 0,
  "translations": [
    {
      "language_id": "uuid",
      "name": "Sport",
      "description": "Sports related content"
    }
  ]
}

Field Type Required Constraints
slug string 2–255 characters, unique
parent_id UUID Must exist in DB
is_active bool Default: true
order int Default: 0, min: 0
translations array List of translations

Response 201 Created — full CategoryResponse object.

Errors

Status Description
404 Parent category not found
409 Category slug already exists

Get Category

GET /api/v1/categories/{id}

Required permission: categories:read

Response 200 OK

{
  "id": "uuid",
  "slug": "sport",
  "parent_id": null,
  "is_active": true,
  "order": 0,
  "created_by": "uuid",
  "translations": [
    {
      "id": "uuid",
      "category_id": "uuid",
      "language_id": "uuid",
      "name": "Sport",
      "description": "Sports related content",
      "created_at": "2026-01-01T00:00:00Z",
      "updated_at": null
    }
  ],
  "created_at": "2026-01-01T00:00:00Z",
  "updated_at": null
}

Errors

Status Description
404 Category not found

Get Category Children

Returns direct children of a category.

GET /api/v1/categories/{id}/children

Required permission: categories:read

Response 200 OK — list of CategorySummary objects.

Errors

Status Description
404 Category not found

Update Category

PATCH /api/v1/categories/{id}

Required permission: categories:update

Request body — all fields optional

{
  "slug": "sports",
  "parent_id": "uuid",
  "is_active": true,
  "order": 1,
  "translations": [
    {
      "language_id": "uuid",
      "name": "Sports",
      "description": "Sports description"
    }
  ]
}

translations is an optional list — if provided, each entry is upserted by the category_id + language_id combination. Existing translations for a given language will be updated; if no translation exists for that language, a new record will be created.

Response 200 OK — updated CategoryResponse object.

Errors

Status Description
400 Category cannot be its own parent
400 Circular category hierarchy is not allowed
404 Category not found
404 Parent category not found
404 Language not found
409 Category slug already exists

Delete Category

Soft-deletes a category. Cannot delete a category that has active children.

DELETE /api/v1/categories/{id}

Required permission: categories:delete

Response 204 No Content

Errors

Status Description
400 Cannot delete category with active children
404 Category not found

Warning

Delete or reassign all children before deleting a parent category.


Upsert Translation

Creates or updates a translation for a specific language. If a translation for the given language already exists, it will be updated.

PUT /api/v1/categories/{id}/translations

Required permission: categories:update

Request body

{
  "language_id": "uuid",
  "name": "Sport",
  "description": "Sports related content"
}

Field Type Required Constraints
language_id UUID Must exist in DB
name string Min 1 character
description string

Response 200 OK — updated CategoryResponse object.

Errors

Status Description
404 Category not found
404 Language not found

Delete Translation

Removes a translation for a specific language from a category.

DELETE /api/v1/categories/{id}/translations/{language_id}

Required permission: categories:update

Response 200 OK — updated CategoryResponse object.

Errors

Status Description
404 Category not found
404 Translation not found