Categories
Categories let you organise posts into thematic groups with a hierarchical structure. A category can contain subcategories, and those subcategories can contain further subcategories. Use them to build blog navigation menus, category pages with filtered posts, or thematic sections on your site. The API returns the full tree in a single request.
GET /categories — Category tree
Returns all categories for a website organised as a tree. There is no pagination — the response always includes the full tree. This is intentional: category trees are typically small (at most a few dozen nodes) and having them all at once greatly simplifies the frontend logic for building menus and navigation. Root categories have parent_id: null; their children are nested under the children field.
| Parameter | Type | Required | Description |
|---|---|---|---|
web_id | string | Yes | Website ID |
lang | string | No | Language code |
curl "https://your-panel.com/api/v1/categories?web_id=abc-123&lang=en" \
-H "X-API-Key: your-api-key" Expected response 200 OK
{
"data": [
{
"id": "cat-001",
"nombre": "Technology",
"slug": "technology",
"description": null,
"parent_id": null,
"children": [
{
"id": "cat-002",
"nombre": "APIs",
"slug": "apis",
"description": "Everything about REST and GraphQL APIs",
"parent_id": "cat-001",
"children": []
}
]
},
{
"id": "cat-003",
"nombre": "Design",
"slug": "design",
"description": null,
"parent_id": null,
"children": []
}
]
} Response fields
| Field | Type | Description |
|---|---|---|
id | UUID | Unique identifier |
nombre | string | Category name |
slug | string | URL-friendly string |
description | string | null | Optional description |
parent_id | UUID | null | Parent ID. null if root category |
children | array | Nested child categories (same structure, recursive) |
The children structure is recursive: each element has exactly the same fields as the parent category, including its own children. To traverse the full tree use a recursive function:
// Flatten the tree into a plain array of categories
function flattenCategories(categories, depth = 0) {
return categories.reduce((acc, cat) => {
acc.push({ ...cat, depth, children: undefined })
if (cat.children && cat.children.length > 0) {
acc.push(...flattenCategories(cat.children, depth + 1))
}
return acc
}, [])
}
// Render as a nested menu (HTML example)
function renderMenu(categories) {
if (!categories || categories.length === 0) return ''
const items = categories.map(cat => {
const sub = cat.children?.length > 0
? `<ul>${renderMenu(cat.children)}</ul>`
: ''
return `<li><a href="/blog/category/${cat.slug}">${cat.nombre}</a>${sub}</li>`
})
return items.join('')
} Use cases
Blog navigation menu. Call this endpoint once at build time (or in a server component) and use the result to render a menu with dropdown support for subcategories. With the tree already structured, you don't need any additional grouping logic.
/category/[slug] pages. Generate a static route for each category using its slugs. In the route, use the category parameter from the posts endpoint to get the filtered posts: /api/v1/posts?web_id=...&category=technology. Combine both calls to have the category name and its posts on the same page.
"More in [category]" section. At the end of each post, show related posts from the same category. You have the category slug in the post's categories field — use it directly in the filter.
Dynamic breadcrumbs. With the parent_id field you can reconstruct the breadcrumb path from any category up to the root by traversing the tree upwards.
Tips and best practices
- Cache the category tree aggressively — it changes very rarely compared to posts. A TTL of several hours, or manual invalidation when a category is modified, is sufficient.
- Always use the
slugto build category URLs, never theid. The slug is designed to appear in URLs and is readable by both users and search engines. - Check that
childrenexists and has elements before iterating over it. Although the API always returns the field, it may be an empty array[]. - If you use Astro with static generation, call this endpoint inside
getStaticPathsto generate all category pages at build time with no runtime requests.
Common errors
| Code | Likely cause | Fix |
|---|---|---|
401 | API Key not included or incorrect | Check the X-API-Key header and that the key is active in the panel |
400 | Missing web_id parameter | Include web_id in the query string |
200 with data: [] | The website has no categories yet | Create at least one category from the panel before calling the endpoint |