> ## Documentation Index
> Fetch the complete documentation index at: https://docs.adminest.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Categories API

> Create, read, update, and delete categories — including the new emoji and colour fields

## Overview

The Categories API lets you manage the colour-coded category labels that group your documents and tasks. Each category has a **name**, an **emoji**, and a **colour**, and is scoped to a single user.

All endpoints are authenticated. Include a valid Auth0 access token in the `Authorization` header:

```
Authorization: Bearer <ACCESS_TOKEN>
```

The API base URL is:

```
https://adminest-backend.delightfulpebble-f95388de.eastus.azurecontainerapps.io
```

## The Category object

| Field           | Type           | Notes                                                                                                                  |
| --------------- | -------------- | ---------------------------------------------------------------------------------------------------------------------- |
| `_id`           | string         | MongoDB ObjectId for the category                                                                                      |
| `userId`        | string         | The owning user. Inferred from the bearer token on create.                                                             |
| `name`          | string         | Display name, up to 60 characters. Must be unique within a user.                                                       |
| `emoji`         | string \| null | A single emoji (e.g. `"🏥"`). May be `null` for "no emoji".                                                            |
| `color`         | string \| null | A hex colour (`#RRGGBB`) used to tint the pill background. May be `null` to use the default neutral tone.              |
| `isSystem`      | boolean        | `true` for seed categories Adminest creates on signup. System categories can be renamed and restyled, but not deleted. |
| `documentCount` | number         | Read-only. The number of documents currently tagged with this category.                                                |
| `taskCount`     | number         | Read-only. The number of tasks currently tagged.                                                                       |
| `createdAt`     | string         | ISO 8601 timestamp.                                                                                                    |
| `updatedAt`     | string         | ISO 8601 timestamp.                                                                                                    |

### Example

```json theme={null}
{
  "_id": "65f1c0a4f1a2b3c4d5e6f7a8",
  "userId": "65f1bff4f1a2b3c4d5e6f700",
  "name": "Insurance",
  "emoji": "🏥",
  "color": "#10b981",
  "isSystem": true,
  "documentCount": 9,
  "taskCount": 3,
  "createdAt": "2026-02-01T08:14:22.041Z",
  "updatedAt": "2026-05-12T19:03:08.918Z"
}
```

<Note>
  The `emoji` and `color` fields are new in V2. Categories created before V2 may return `null` for both — clients should treat that as "use the default neutral tint" and "no emoji".
</Note>

## Endpoints

### List categories

```http theme={null}
GET /api/categories
```

Returns every category for the authenticated user, including their `documentCount` and `taskCount`.

<CodeGroup>
  ```bash cURL theme={null}
  curl -X GET https://adminest-backend.../api/categories \
    -H "Authorization: Bearer $TOKEN"
  ```

  ```javascript Node theme={null}
  const res = await fetch('https://adminest-backend.../api/categories', {
    headers: { Authorization: `Bearer ${token}` },
  });
  const categories = await res.json();
  ```
</CodeGroup>

**Response — `200 OK`**

```json theme={null}
[
  {
    "_id": "65f1c0a4f1a2b3c4d5e6f7a8",
    "name": "Insurance",
    "emoji": "🏥",
    "color": "#10b981",
    "isSystem": true,
    "documentCount": 9,
    "taskCount": 3,
    "createdAt": "2026-02-01T08:14:22.041Z",
    "updatedAt": "2026-05-12T19:03:08.918Z"
  },
  {
    "_id": "65f1c0a4f1a2b3c4d5e6f7a9",
    "name": "Utilities",
    "emoji": "⚡",
    "color": "#f59e0b",
    "isSystem": true,
    "documentCount": 12,
    "taskCount": 2,
    "createdAt": "2026-02-01T08:14:22.041Z",
    "updatedAt": "2026-04-20T11:24:08.918Z"
  }
]
```

### Create a category

```http theme={null}
POST /api/categories
```

Creates a new category for the authenticated user. `name` is required; `emoji` and `color` are optional.

**Request body**

```json theme={null}
{
  "name": "Pet",
  "emoji": "🐾",
  "color": "#db2777"
}
```

| Field   | Type   | Required | Validation                                    |
| ------- | ------ | -------- | --------------------------------------------- |
| `name`  | string | yes      | 1–60 chars; unique per user                   |
| `emoji` | string | no       | A single emoji grapheme                       |
| `color` | string | no       | Hex colour `#RRGGBB` (lowercase or uppercase) |

<CodeGroup>
  ```bash cURL theme={null}
  curl -X POST https://adminest-backend.../api/categories \
    -H "Authorization: Bearer $TOKEN" \
    -H "Content-Type: application/json" \
    -d '{"name":"Pet","emoji":"🐾","color":"#db2777"}'
  ```

  ```javascript Node theme={null}
  const res = await fetch('https://adminest-backend.../api/categories', {
    method: 'POST',
    headers: {
      Authorization: `Bearer ${token}`,
      'Content-Type': 'application/json',
    },
    body: JSON.stringify({ name: 'Pet', emoji: '🐾', color: '#db2777' }),
  });
  const category = await res.json();
  ```
</CodeGroup>

**Response — `201 Created`**

```json theme={null}
{
  "_id": "65f1c0a4f1a2b3c4d5e6f7b1",
  "userId": "65f1bff4f1a2b3c4d5e6f700",
  "name": "Pet",
  "emoji": "🐾",
  "color": "#db2777",
  "isSystem": false,
  "documentCount": 0,
  "taskCount": 0,
  "createdAt": "2026-05-24T03:18:01.211Z",
  "updatedAt": "2026-05-24T03:18:01.211Z"
}
```

**Errors**

| Status             | When                                                                                        |
| ------------------ | ------------------------------------------------------------------------------------------- |
| `400 Bad Request`  | `name` missing or longer than 60 chars; invalid `color` format; multiple emojis in `emoji`. |
| `401 Unauthorized` | Missing or invalid bearer token.                                                            |
| `409 Conflict`     | A category with this name already exists for the user.                                      |

### Update a category

```http theme={null}
PUT /api/categories/:id
```

Updates the name, emoji, or colour of an existing category. This is the new endpoint introduced in V2 — previously you could only create or delete.

You can update any combination of fields. Fields you don't send are left unchanged.

**Request body**

```json theme={null}
{
  "name": "Pets",
  "emoji": "🐶",
  "color": "#7c3aed"
}
```

| Field   | Type           | Notes                                                         |
| ------- | -------------- | ------------------------------------------------------------- |
| `name`  | string         | Optional. 1–60 chars; must remain unique for the user.        |
| `emoji` | string \| null | Optional. Send `null` to remove the emoji.                    |
| `color` | string \| null | Optional. Send `null` to use the default tint. Hex `#RRGGBB`. |

<CodeGroup>
  ```bash cURL theme={null}
  curl -X PUT https://adminest-backend.../api/categories/65f1c0a4f1a2b3c4d5e6f7b1 \
    -H "Authorization: Bearer $TOKEN" \
    -H "Content-Type: application/json" \
    -d '{"name":"Pets","emoji":"🐶","color":"#7c3aed"}'
  ```

  ```javascript Node theme={null}
  const res = await fetch(
    `https://adminest-backend.../api/categories/${id}`,
    {
      method: 'PUT',
      headers: {
        Authorization: `Bearer ${token}`,
        'Content-Type': 'application/json',
      },
      body: JSON.stringify({ name: 'Pets', emoji: '🐶', color: '#7c3aed' }),
    }
  );
  const updated = await res.json();
  ```
</CodeGroup>

**Response — `200 OK`**

```json theme={null}
{
  "_id": "65f1c0a4f1a2b3c4d5e6f7b1",
  "userId": "65f1bff4f1a2b3c4d5e6f700",
  "name": "Pets",
  "emoji": "🐶",
  "color": "#7c3aed",
  "isSystem": false,
  "documentCount": 0,
  "taskCount": 0,
  "createdAt": "2026-05-24T03:18:01.211Z",
  "updatedAt": "2026-05-24T03:19:44.001Z"
}
```

**Errors**

| Status             | When                                                                                                |
| ------------------ | --------------------------------------------------------------------------------------------------- |
| `400 Bad Request`  | Invalid `color`, multiple emojis in `emoji`, or empty `name`.                                       |
| `401 Unauthorized` | Missing or invalid bearer token.                                                                    |
| `403 Forbidden`    | Attempt to rename or restyle a system category in a forbidden way (e.g. unsetting required fields). |
| `404 Not Found`    | The category doesn't exist or doesn't belong to the authenticated user.                             |
| `409 Conflict`     | Another category with that name already exists for the user.                                        |

<Note>
  System categories (created automatically when you signed up) **can** be renamed, recoloured, and re-emojied via this endpoint, but cannot be deleted.
</Note>

### Delete a category

```http theme={null}
DELETE /api/categories/:id
```

Removes a user-created category. Any documents or tasks that were tagged with it are un-tagged automatically.

<CodeGroup>
  ```bash cURL theme={null}
  curl -X DELETE https://adminest-backend.../api/categories/65f1c0a4f1a2b3c4d5e6f7b1 \
    -H "Authorization: Bearer $TOKEN"
  ```
</CodeGroup>

**Response — `200 OK`**

```json theme={null}
{
  "success": true,
  "deletedId": "65f1c0a4f1a2b3c4d5e6f7b1"
}
```

**Errors**

| Status             | When                                                                                       |
| ------------------ | ------------------------------------------------------------------------------------------ |
| `401 Unauthorized` | Missing or invalid bearer token.                                                           |
| `403 Forbidden`    | The category is a system category (`isSystem: true`). System categories cannot be deleted. |
| `404 Not Found`    | The category doesn't exist or doesn't belong to the authenticated user.                    |

### Suggest categories for a document

```http theme={null}
POST /api/categories/suggest
```

Returns AI-ranked category suggestions for a document, based on its content and the user's existing categories. Suggestions are advisory — the client decides whether to apply them.

**Request body**

```json theme={null}
{
  "documentData": {
    "title": "AA Insurance — home and contents renewal",
    "summary": "Annual renewal notice for home and contents policy…",
    "type": "insurance"
  }
}
```

**Response — `200 OK`**

```json theme={null}
[
  { "categoryId": "65f1c0a4f1a2b3c4d5e6f7a8", "name": "Insurance", "score": 0.94 },
  { "categoryId": "65f1c0a4f1a2b3c4d5e6f7c2", "name": "Property", "score": 0.61 }
]
```

<Note>
  AI-suggested categories are not enabled for every account yet. When the feature is off, this endpoint returns an empty array.
</Note>

## Field validation reference

### `color`

Adminest validates the colour as a hex string in the `#RRGGBB` form. Both uppercase and lowercase digits are accepted.

```text theme={null}
✅  #08B7F0
✅  #10b981
❌  #08B7F  (too short)
❌  rgb(8, 183, 240)  (not hex)
❌  blue  (not hex)
```

If you send `null` (or omit the field on create), Adminest uses a neutral grey tint when rendering the category.

### `emoji`

The `emoji` field accepts a **single emoji grapheme**, including emoji that are technically multiple codepoints (e.g. `"👨‍👩‍👧"`). Plain text is rejected.

```text theme={null}
✅  "🏥"
✅  "👨‍👩‍👧"
❌  "Insurance"      (not an emoji)
❌  "🏥🛡️"          (two emojis)
```

Send `null` (or omit on create) for "no emoji".

## Related

<CardGroup cols={2}>
  <Card title="Documents" icon="file-lines" href="/guide/documents">
    Apply categories from the UI
  </Card>

  <Card title="Categories guide" icon="palette" href="/guide/account">
    User-facing guide to managing categories
  </Card>
</CardGroup>
