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

# Sub-Categories API

> Create, update, list, and delete sub-categories within offer categories.

Sub-categories live under a category and group related offers. They support soft-delete, version tracking, and audit logging. For the full sub-categories documentation integrated with the Categories API, see the [Categories API reference](/api-reference/categories).

All sub-categories support **soft-delete** (a `deletedAt` timestamp is set instead of permanent removal), **version tracking** (the `version` field auto-increments on every update), and **audit logging** (before/after snapshots are recorded for every CRUD operation).

## Base path

```
/api/v1/sub-categories
```

***

## List sub-categories

```
GET /api/v1/sub-categories
```

Returns a paginated list of sub-categories for the tenant, ordered by `ordinal` ascending. Optionally filter by parent category. By default, soft-deleted sub-categories are excluded.

### Query Parameters

| Parameter        | Type    | Required | Description                                                              |
| ---------------- | ------- | -------- | ------------------------------------------------------------------------ |
| `categoryId`     | string  | No       | Filter by parent category ID.                                            |
| `limit`          | integer | No       | Maximum results per page. Default `50`, max `100`.                       |
| `cursor`         | string  | No       | Cursor for keyset pagination. Pass the last `id` from the previous page. |
| `includeDeleted` | string  | No       | Set to `"true"` to include soft-deleted sub-categories.                  |

### Response `200`

```json theme={null}
{
  "data": [
    {
      "id": "sub_01",
      "tenantId": "t_001",
      "categoryId": "cat_01",
      "name": "Premium Cards",
      "description": "High-tier credit card products",
      "icon": "",
      "status": "active",
      "ordinal": 0,
      "version": 1,
      "deletedAt": null,
      "customFields": [],
      "category": { "id": "cat_01", "name": "Acquisition" },
      "_count": { "offers": 12 },
      "createdAt": "2026-03-10T12:00:00.000Z",
      "updatedAt": "2026-03-10T12:00:00.000Z"
    }
  ],
  "pagination": {
    "limit": 50,
    "cursor": null,
    "hasMore": false,
    "total": 3
  }
}
```

***

## Create a sub-category

```
POST /api/v1/sub-categories
```

### Request Body

| Field          | Type           | Required | Description                                                |
| -------------- | -------------- | -------- | ---------------------------------------------------------- |
| `categoryId`   | string         | **Yes**  | Parent category ID.                                        |
| `name`         | string         | **Yes**  | Sub-category name.                                         |
| `description`  | string         | No       | Optional description.                                      |
| `icon`         | string         | No       | Icon identifier.                                           |
| `status`       | enum           | No       | `"active"` (default), `"draft"`, `"paused"`, `"archived"`. |
| `ordinal`      | integer (>= 0) | No       | Sort order. Default `0`.                                   |
| `customFields` | array          | No       | Custom field definitions (same schema as categories).      |

### Example

```bash theme={null}
curl -X POST https://playground.kaireonai.com/api/v1/sub-categories \
  -H "Content-Type: application/json" \
  -H "X-Tenant-Id: my-tenant" \
  -d '{
    "categoryId": "cat_credit_cards",
    "name": "Premium Cards",
    "description": "High-tier credit card products",
    "status": "active"
  }'
```

### Response `201`

Returns the created sub-category with its parent category relation, `version: 1`, and `deletedAt: null`. An audit log entry is created with a `create` action.

### Error codes

| Code  | Reason                                                                                                                                                     |
| ----- | ---------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `400` | Validation error — missing `categoryId`/`name`, or a `categoryId` that doesn't exist in your tenant (the parent category's tenant ownership is validated). |
| `401` | Missing or invalid API key / session.                                                                                                                      |
| `403` | Insufficient role (requires `editor` or `admin`).                                                                                                          |
| `409` | A sub-category with that name already exists.                                                                                                              |
| `413` | Request body exceeds the 2 MB limit.                                                                                                                       |
| `415` | `Content-Type` is not `application/json`.                                                                                                                  |

***

## Update a sub-category

```
PUT /api/v1/sub-categories
```

Updates an existing sub-category. Only provided fields are changed. The `version` field is auto-incremented and a before/after audit snapshot is recorded.

### Request Body

| Field | Type   | Required | Description                |
| ----- | ------ | -------- | -------------------------- |
| `id`  | string | **Yes**  | Sub-category ID to update. |

All other fields from the create schema are accepted as optional.

### Response `200`

Returns the updated sub-category object with the incremented `version`.

### Error codes

| Code  | Reason                                                   |
| ----- | -------------------------------------------------------- |
| `400` | Validation error or missing `id`.                        |
| `401` | Missing or invalid API key / session.                    |
| `403` | Insufficient role.                                       |
| `404` | No sub-category with that `id` (or name) in your tenant. |
| `409` | A sub-category with that name already exists.            |
| `413` | Request body exceeds the 2 MB limit.                     |
| `415` | `Content-Type` is not `application/json`.                |

***

## Delete a sub-category (soft-delete)

```
DELETE /api/v1/sub-categories?id={subCategoryId}
```

Soft-deletes a sub-category by setting its `deletedAt` timestamp. The `version` is incremented.

### Query Parameters

| Parameter | Type   | Required | Description                |
| --------- | ------ | -------- | -------------------------- |
| `id`      | string | **Yes**  | Sub-category ID to delete. |

### Response `200`

```json theme={null}
{
  "success": true
}
```

### Error codes

| Code  | Reason                                                   |
| ----- | -------------------------------------------------------- |
| `400` | Missing `id`, or soft-delete failed.                     |
| `401` | Missing or invalid API key / session.                    |
| `403` | Insufficient role.                                       |
| `404` | No sub-category with that `id` (or name) in your tenant. |

<Note>
  To restore a soft-deleted sub-category, use `POST /api/v1/restore?entityType=subCategory&id={subCategoryId}` (admin only).
</Note>

***

## Role requirements

| Method | Minimum role |
| ------ | ------------ |
| GET    | `viewer`     |
| POST   | `editor`     |
| PUT    | `editor`     |
| DELETE | `editor`     |
