Skip to main content

Admin Categories API Endpoints

The Admin Categories API provides full CRUD operations for managing content categories, including reordering and Git-based synchronization with a remote data repository. All endpoints require admin authentication via session-based auth.

Route Summary

MethodPathAuthDescription
GET/api/admin/categoriesAdminList categories (paginated)
POST/api/admin/categoriesAdminCreate a new category
GET/api/admin/categories/allAdminGet all categories (from content cache)
GET/api/admin/categories/{id}AdminGet a single category by ID
PUT/api/admin/categories/{id}AdminUpdate a category
DELETE/api/admin/categories/{id}AdminSoft or hard delete a category
PUT/api/admin/categories/reorderAdminReorder categories by ID array
GET/api/admin/categories/gitAdminGet Git repo status and categories
POST/api/admin/categories/gitAdminCreate category via Git commit

Authentication

All category management endpoints check for an active session with admin privileges:

const session = await auth();
if (!session?.user?.isAdmin) {
return NextResponse.json(
{ success: false, error: "Unauthorized. Admin access required." },
{ status: 401 }
);
}

Endpoints

GET /api/admin/categories

Returns a paginated list of categories with optional filtering and sorting.

Query Parameters:

ParameterTypeDefaultDescription
pageinteger1Page number (minimum: 1)
limitinteger10Items per page (1--100)
includeInactivestring"false"Include inactive categories
sortBystring"name"Sort field: "name" or "id"
sortOrderstring"asc"Sort direction: "asc" or "desc"

Response (200):

{
"success": true,
"categories": [
{
"id": "productivity",
"name": "Productivity",
"isActive": true,
"itemCount": 15,
"createdAt": "2024-01-15T10:30:00.000Z",
"updatedAt": "2024-01-15T10:30:00.000Z"
}
],
"total": 25,
"page": 1,
"limit": 10,
"totalPages": 3
}

POST /api/admin/categories

Creates a new category. The id field is optional and will be auto-generated from the name if not provided. Invalidates content caches on success.

Request Body:

{
"id": "productivity",
"name": "Productivity"
}
FieldTypeRequiredDescription
idstringNoURL-friendly slug (^[a-z0-9-]+$). Auto-generated if omitted.
namestringYesDisplay name (2--100 characters)

Response (201):

{
"success": true,
"category": {
"id": "productivity",
"name": "Productivity",
"isActive": true,
"itemCount": 0,
"createdAt": "2024-01-20T15:30:00.000Z",
"updatedAt": "2024-01-20T15:30:00.000Z"
},
"message": "Category created successfully"
}

GET /api/admin/categories/all

Returns all categories from the content cache for a given locale. Useful for admin dropdowns and selectors.

Query Parameters:

ParameterTypeDefaultDescription
localestring"en"Locale code for content retrieval

Response (200):

{
"success": true,
"data": [
{ "id": "productivity", "name": "Productivity", "isActive": true, "itemCount": 15 }
]
}

GET /api/admin/categories/{id}

Retrieves a single category by its unique identifier.

Response (200):

{
"success": true,
"data": {
"id": "productivity",
"name": "Productivity",
"isActive": true,
"itemCount": 15,
"createdAt": "2024-01-15T10:30:00.000Z",
"updatedAt": "2024-01-15T10:30:00.000Z"
}
}

PUT /api/admin/categories/{id}

Updates the name of an existing category. Invalidates content caches on success.

Request Body:

{ "name": "Productivity Tools" }

Response (200):

{
"success": true,
"data": { "id": "productivity", "name": "Productivity Tools", "isActive": true },
"message": "Category updated successfully"
}

DELETE /api/admin/categories/{id}

Deletes a category. By default performs a soft delete (deactivation). Use the hard=true query parameter for permanent deletion. Invalidates content caches on success.

Query Parameters:

ParameterTypeDefaultDescription
hardstring"false"Set to "true" for permanent deletion

Response (200):

{
"success": true,
"message": "Category deactivated successfully"
}

PUT /api/admin/categories/reorder

Reorders categories based on an array of category IDs. The position of each ID in the array determines its new display order.

Request Body:

{ "categoryIds": ["productivity", "design", "development", "marketing"] }

Validation Rules:

  • categoryIds must be a non-empty array
  • All values must be strings

Response (200):

{
"success": true,
"message": "Categories reordered successfully"
}

GET /api/admin/categories/git

Fetches the Git repository status and categories from the configured GitHub data repository. Requires DATA_REPOSITORY and GITHUB_TOKEN environment variables.

Response (200):

{
"success": true,
"status": {
"repository": "ever-co/awesome-time-tracking-data",
"branch": "main",
"lastCommit": "abc123def456",
"lastCommitDate": "2024-01-20T10:30:00.000Z",
"isUpToDate": true
},
"categories": [],
"message": "Git repository status retrieved successfully"
}

POST /api/admin/categories/git

Creates a new category and commits it directly to the GitHub data repository. Requires DATA_REPOSITORY and GH_TOKEN environment variables.

Request Body:

{ "id": "productivity", "name": "Productivity" }

Both id and name are required for Git-based creation.

Response (200):

{
"success": true,
"category": { "id": "productivity", "name": "Productivity" },
"message": "Category created and committed to Git repository"
}

Error Codes

StatusErrorCause
400Invalid pagination parametersPage < 1 or limit outside 1--100
400Category name is requiredMissing name in create request
400categoryIds must be an arrayInvalid reorder payload
401Unauthorized. Admin access required.Missing or non-admin session
404Category not foundInvalid category ID
409Category with this name already existsDuplicate name on create/update
500DATA_REPOSITORY not configuredMissing env var for Git endpoints
500GitHub token not configuredMissing GITHUB_TOKEN or GH_TOKEN

Cache Invalidation

All write operations (create, update, delete, reorder) call invalidateContentCaches() to ensure changes are immediately visible across the application.