Categories
List 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.
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
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
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.
Required permission: categories:read
Response 200 OK — list of CategorySummary objects.
Errors
| Status | Description |
|---|---|
404 |
Category not found |
Update Category
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"
}
]
}
translationsis an optional list — if provided, each entry is upserted by thecategory_id + language_idcombination. 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.
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.
Required permission: categories:update
Request body
| 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.
Required permission: categories:update
Response 200 OK — updated CategoryResponse object.
Errors
| Status | Description |
|---|---|
404 |
Category not found |
404 |
Translation not found |