Skip to main content
POST
/
api
/
categories
Create Category
curl --request POST \
  --url https://api.example.com/api/categories \
  --header 'Content-Type: application/json' \
  --data '
{
  "name": "<string>",
  "type": {},
  "isFixed": true,
  "color": "<string>",
  "icon": "<string>",
  "parentId": "<string>"
}
'
{
  "id": "<string>",
  "userId": "<string>",
  "name": "<string>",
  "type": "<string>",
  "isFixed": true,
  "color": "<string>",
  "icon": "<string>",
  "parentId": "<string>",
  "createdAt": "<string>",
  "updatedAt": "<string>",
  "deletedAt": "<string>"
}

Endpoint

POST /api/categories
Creates a new category for the authenticated user. Categories can be standalone or nested within a parent category (up to 2 levels deep).

Authentication

Requires JWT authentication via Authorization: Bearer <token> header.

Request Body

name
string
required
Category name (2-50 characters)
type
enum
required
Category type. One of:
  • INCOME - For income transactions
  • EXPENSE - For expense transactions
  • BOTH - Can be used for both income and expenses
isFixed
boolean
default:"false"
Whether this is a fixed monthly expense (e.g., rent, subscriptions)
color
string
Hex color code for the category (e.g., #FF5733). Must match pattern ^#[0-9A-Fa-f]{6}$
icon
string
Icon identifier for the category (max 50 characters)
parentId
string
UUID of the parent category to create a subcategory. Parent must:
  • Exist and belong to the authenticated user
  • Not itself be a subcategory (2-level nesting limit)

Validation Rules

  • Name uniqueness: Category name must be unique per user, type, and parent combination
  • Hierarchical validation:
    • Parent category must exist and belong to the user
    • Cannot create subcategories of subcategories (max 2 levels)
    • Cannot reference itself as parent

Response

id
string
Unique identifier (UUID) of the created category
userId
string
ID of the user who owns this category
name
string
Category name
type
string
Category type (INCOME, EXPENSE, or BOTH)
isFixed
boolean
Whether this is a fixed monthly expense
color
string
Hex color code for the category
icon
string
Icon identifier
parentId
string
ID of the parent category (null for root categories)
createdAt
string
ISO 8601 timestamp of creation
updatedAt
string
ISO 8601 timestamp of last update
deletedAt
string
ISO 8601 timestamp of soft deletion (null if not deleted)

Example Request

{
  "name": "Streaming Services",
  "type": "EXPENSE",
  "isFixed": true,
  "color": "#9B59B6",
  "icon": "tv",
  "parentId": "550e8400-e29b-41d4-a716-446655440000"
}

Example Response

{
  "id": "123e4567-e89b-12d3-a456-426614174000",
  "userId": "user-uuid-here",
  "name": "Streaming Services",
  "type": "EXPENSE",
  "isFixed": true,
  "color": "#9B59B6",
  "icon": "tv",
  "parentId": "550e8400-e29b-41d4-a716-446655440000",
  "createdAt": "2026-03-04T10:30:00.000Z",
  "updatedAt": "2026-03-04T10:30:00.000Z",
  "deletedAt": null
}

Error Responses

409 Conflict

{
  "statusCode": 409,
  "message": "Category \"Streaming Services\" already exists"
}

404 Not Found

{
  "statusCode": 404,
  "message": "Parent category not found"
}

400 Bad Request

{
  "statusCode": 400,
  "message": "Nesting limit reached. Cannot create a subcategory of a subcategory."
}

Build docs developers (and LLMs) love