---
title: "Shelves API"
description: "Use when you list, create, rename, delete or fill shelves over HTTP. A shelf is a named group of your books, addressed by id or slug."
url: https://docs.heytrove.ai/reference/api/shelves
updated: 2026-10-01
---

# Shelves API

> Load this page when: you need to manage shelves or the books on them over HTTP

## For agents

- Address a shelf by id or slug in the path.
- Add books in batches. Books you cannot access come back in notFound.
- Remove books with a comma-separated itemIds query, not a body.

A shelf groups books and tells the librarian what to prefer. See [Shelves](https://docs.heytrove.ai/concepts/shelves.md).

## List shelves

`GET https://heytrove.ai/api/v1/shelves`

Lists your shelves in display order. It takes no parameters.

**Request**

```bash
curl https://heytrove.ai/api/v1/shelves \
  -H "Authorization: Bearer trove_your_key"
```

**Response**

```json
{
  "shelves": [
    { "id": "cmshelf1", "name": "Backend", "slug": "backend", "color": "#5B7CFA", "position": 0, "itemCount": 4 }
  ]
}
```

**CLI equivalent**: [trove shelf list](https://docs.heytrove.ai/reference/cli/shelf.md#trove-shelf-list).

## Get a shelf

`GET https://heytrove.ai/api/v1/shelves/{id}`

Returns one shelf and its books, with the same item fields as [List items](https://docs.heytrove.ai/reference/api/items.md#list-items).

**Parameters**

| Name | In | Type | Required | Constraints | Meaning |
| --- | --- | --- | --- | --- | --- |
| `id` | path | string | yes | shelf id or slug | Shelf to show. |

**Request**

```bash
curl https://heytrove.ai/api/v1/shelves/backend \
  -H "Authorization: Bearer trove_your_key"
```

**Response**

```json
{
  "shelf": { "id": "cmshelf1", "name": "Backend", "slug": "backend", "color": "#5B7CFA", "position": 0, "itemCount": 4 },
  "items": [],
  "enrichmentQueue": null,
  "pickUrl": null
}
```

`items` holds the books. `pickUrl` is set only when a book on the shelf is locked.

**Errors**

| Status | Message | Code | Fix |
| --- | --- | --- | --- |
| 404 | `Shelf not found` | `SHELF_NOT_FOUND` | Check the id or slug. |

**CLI equivalent**: [trove shelf show](https://docs.heytrove.ai/reference/cli/shelf.md#trove-shelf-show).

## Create a shelf

`POST https://heytrove.ai/api/v1/shelves`

Creates a shelf. The slug comes from the name. Names are unique per user.

**Parameters**

| Name | In | Type | Required | Constraints | Meaning |
| --- | --- | --- | --- | --- | --- |
| `name` | body | string | yes | 1 to 50 characters | Display name. |
| `color` | body | string | no | `#RRGGBB` | Six-digit hex color. A value in any other shape is ignored. |

**Request**

```bash
curl https://heytrove.ai/api/v1/shelves \
  -H "Authorization: Bearer trove_your_key" \
  -H "Content-Type: application/json" \
  -d '{"name":"Backend","color":"#5B7CFA"}'
```

**Response**

Status 201.

```json
{ "id": "cmshelf1", "name": "Backend", "slug": "backend", "color": "#5B7CFA", "position": 0, "itemCount": 0 }
```

**Errors**

| Status | Message | Code | Fix |
| --- | --- | --- | --- |
| 400 | `Name is required and must be 50 characters or less` | `INVALID_INPUT` | Send a shorter name. |
| 400 | `Invalid shelf name` | `SHELF_NAME_INVALID` | Use letters or digits. |
| 409 | `A shelf with this name already exists` | `SHELF_NAME_TAKEN` | Pick another name. |
| 403 | `Shelf limit reached ({n}). Delete an unused shelf to make room.` | `SHELF_LIMIT_EXCEEDED` | Delete a shelf you no longer use. |

**CLI equivalent**: [trove shelf create](https://docs.heytrove.ai/reference/cli/shelf.md#trove-shelf-create).

## Update a shelf

`PATCH https://heytrove.ai/api/v1/shelves/{id}`

Renames a shelf, changes its color or moves its position. Send only the fields you want to change.

**Parameters**

| Name | In | Type | Required | Constraints | Meaning |
| --- | --- | --- | --- | --- | --- |
| `id` | path | string | yes | shelf id or slug | Shelf to change. |
| `name` | body | string | no | 1 to 50 characters | New name. The slug changes with it. |
| `color` | body | string or null | no | `#RRGGBB` | New color. `null` clears it. |
| `position` | body | integer | no | 0 or more | New position in the list. |

**Request**

```bash
curl -X PATCH https://heytrove.ai/api/v1/shelves/backend \
  -H "Authorization: Bearer trove_your_key" \
  -H "Content-Type: application/json" \
  -d '{"name":"Backend services"}'
```

**Response**

The updated shelf, in the same shape as Create a shelf.

**Errors**

| Status | Message | Code | Fix |
| --- | --- | --- | --- |
| 400 | `Name must be 1-50 characters` | `INVALID_INPUT` | Fix the name. |
| 400 | `Position must be a non-negative integer` | `INVALID_INPUT` | Use 0 or more. |
| 404 | `Shelf not found` | `SHELF_NOT_FOUND` | Check the id or slug. |
| 409 | `A shelf with this name already exists` | `SHELF_NAME_TAKEN` | Pick another name. |

**CLI equivalent**: [trove shelf rename](https://docs.heytrove.ai/reference/cli/shelf.md#trove-shelf-rename).

## Delete a shelf

`DELETE https://heytrove.ai/api/v1/shelves/{id}`

Deletes a shelf. The books stay in your library.

**Request**

```bash
curl -X DELETE https://heytrove.ai/api/v1/shelves/backend \
  -H "Authorization: Bearer trove_your_key"
```

**Response**

```json
{ "success": true }
```

**Errors**

| Status | Message | Code | Fix |
| --- | --- | --- | --- |
| 404 | `Shelf not found` | `SHELF_NOT_FOUND` | Check the id or slug. |

**CLI equivalent**: [trove shelf delete](https://docs.heytrove.ai/reference/cli/shelf.md#trove-shelf-delete).

## Add books to a shelf

`POST https://heytrove.ai/api/v1/shelves/{id}/items`

Adds books to a shelf. Adding a book that is already there changes nothing.

**Parameters**

| Name | In | Type | Required | Constraints | Meaning |
| --- | --- | --- | --- | --- | --- |
| `id` | path | string | yes | shelf id or slug | Target shelf. |
| `itemIds` | body | string array | yes | 1 to 200 ids | Books to add. |

**Request**

```bash
curl https://heytrove.ai/api/v1/shelves/backend/items \
  -H "Authorization: Bearer trove_your_key" \
  -H "Content-Type: application/json" \
  -d '{"itemIds":["cmabc123","cmdef456"]}'
```

**Response**

Status 201 when every book was added, and 207 when some were not.

```json
{ "added": ["cmabc123"], "notFound": ["cmdef456"] }
```

**Errors**

| Status | Message | Code | Fix |
| --- | --- | --- | --- |
| 400 | `itemIds must be a non-empty array of strings` | `INVALID_INPUT` | Send ids. |
| 413 | `Too many items in one request (max 200). Split the batch.` | `BATCH_TOO_LARGE` | Split the batch. |
| 404 | `Shelf not found` | `SHELF_NOT_FOUND` | Check the id or slug. |

**CLI equivalent**: [trove shelf add](https://docs.heytrove.ai/reference/cli/shelf.md#trove-shelf-add).

## Remove books from a shelf

`DELETE https://heytrove.ai/api/v1/shelves/{id}/items?itemIds=ID1,ID2`

Removes books from a shelf. The books stay in your library.

**Parameters**

| Name | In | Type | Required | Constraints | Meaning |
| --- | --- | --- | --- | --- | --- |
| `id` | path | string | yes | shelf id or slug | Shelf to change. |
| `itemIds` | query | string | yes | comma-separated, up to 200 ids, up to 8,192 characters | Books to remove. |

**Request**

```bash
curl -X DELETE "https://heytrove.ai/api/v1/shelves/backend/items?itemIds=cmabc123,cmdef456" \
  -H "Authorization: Bearer trove_your_key"
```

**Response**

```json
{ "removed": 2 }
```

**Errors**

| Status | Message | Code | Fix |
| --- | --- | --- | --- |
| 400 | `itemIds query param is required (comma-separated)` | none | Send `itemIds`. |
| 414 | `itemIds query string is too long` | `BATCH_TOO_LARGE` | Split the batch. |
| 413 | `Too many items in one request (max 200). Split the batch.` | `BATCH_TOO_LARGE` | Split the batch. |

**CLI equivalent**: [trove shelf remove](https://docs.heytrove.ai/reference/cli/shelf.md#trove-shelf-remove).
