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

# Manage List Items

Add and remove publications in any list of any user of your store: the favorites list, a custom list the user created, or a list the user collaborates on. What you write here is what the user sees in the storefront and in the reader.

Both endpoints require an administrator token. See the [Lists API Overview](./lists-v3-overview.md) for authentication, the target user parameters and [how a list is addressed](./lists-v3-overview.md#addressing-a-list).

:::info Items only
The API writes the contents of lists, not the lists themselves. It does not create, rename, delete or share lists, does not change list privacy and does not manage collaborators. Those operations exist only in the storefront. The favorites list is the exception, see [Working with favorites](#favorites).
:::

## Both operations are idempotent

These endpoints are not toggles. Repeating a call leaves the list in the same state as the first call did, which makes them safe to retry:

| Call                                      | Result                                                              |
| ----------------------------------------- | ------------------------------------------------------------------- |
| Add a publication that is not in the list | `200`, the publication is added                                     |
| Add a publication that is already there   | `200` with the same body, nothing changes and nothing is duplicated |
| Remove a publication that is in the list  | `204`, the publication is removed                                   |
| Remove a publication that is not there    | `204`, nothing changes                                              |

---

## Add a publication to a list {#add}

Adds the publication to one of the target user's lists.

### Endpoint

```
POST /api/v3/lists/{list}/items
```

### Path parameters

| Parameter | Type   | Description                                                                                                                     |
| --------- | ------ | ------------------------------------------------------------------------------------------------------------------------------- |
| `list`    | string | The `favorites` slug, or the `id` of one of the user's lists. See [Addressing a list](./lists-v3-overview.md#addressing-a-list) |

### Headers

| Header         | Required | Description                        |
| -------------- | -------- | ---------------------------------- |
| `X-User-Token` | Yes      | API token of a store administrator |
| `Content-Type` | Yes      | `application/json`                 |
| `Accept`       | No       | `application/json`                 |

### Body parameters

| Parameter          | Type   | Required    | Default    | Description                                                                                                                     |
| ------------------ | ------ | ----------- | ---------- | ------------------------------------------------------------------------------------------------------------------------------- |
| `user_external_id` | string | Conditional | -          | Your identifier for the user. Required unless `user_email` is sent                                                              |
| `user_email`       | string | Conditional | -          | Email of the user. Required unless `user_external_id` is sent                                                                   |
| `content_id`       | string | Yes         | -          | The publication identifier, read according to `id_type`                                                                         |
| `id_type`          | string | No          | `internal` | `internal` reads `content_id` as the publica.la id; `external` reads it as one of the publication identifiers (ISBN among them) |

Exactly one of `user_external_id` and `user_email` must be sent.

### Request example

```json
{
  "user_external_id": "student-1042",
  "content_id": "9781234567890",
  "id_type": "external"
}
```

### Response

**Success (200):**

The added publication, in the same shape the items endpoints return.

```json
{
  "data": {
    "content_id": "468166",
    "isbn": "9781234567890",
    "title": "Conversations with Donald Hall",
    "reader_url": "https://yourstore.publica.la/reader/conversations-with-donald-hall",
    "added_at": "2026-08-27T12:00:00.000000Z"
  }
}
```

The response is `200` whether this call added the publication or found it already there. `content_id` in the response is always the publica.la id, even when you addressed the publication by ISBN. `added_at` is `null` when the publication was already in the list from before the platform started recording that timestamp.

### Examples

#### Add to favorites by ISBN

```bash
curl -X POST "https://yourstore.publica.la/api/v3/lists/favorites/items" \
  -H "X-User-Token: your-api-token" \
  -H "Content-Type: application/json" \
  -H "Accept: application/json" \
  -d '{"user_external_id": "student-1042", "content_id": "9781234567890", "id_type": "external"}'
```

#### Add to favorites by publica.la id

```bash
curl -X POST "https://yourstore.publica.la/api/v3/lists/favorites/items" \
  -H "X-User-Token: your-api-token" \
  -H "Content-Type: application/json" \
  -H "Accept: application/json" \
  -d '{"user_external_id": "student-1042", "content_id": "468166"}'
```

#### Identify the user by email

```bash
curl -X POST "https://yourstore.publica.la/api/v3/lists/favorites/items" \
  -H "X-User-Token: your-api-token" \
  -H "Content-Type: application/json" \
  -H "Accept: application/json" \
  -d '{"user_email": "student@example.com", "content_id": "468166"}'
```

#### Add to any other list, by id

```bash
curl -X POST "https://yourstore.publica.la/api/v3/lists/9f2d4b1e-6c3a-4f58-9b77-1d0a2e5c8b34/items" \
  -H "X-User-Token: your-api-token" \
  -H "Content-Type: application/json" \
  -H "Accept: application/json" \
  -d '{"user_external_id": "student-1042", "content_id": "468166"}'
```

### Errors

| Status | Message                                                   | Cause                                                                                           |
| ------ | --------------------------------------------------------- | ----------------------------------------------------------------------------------------------- |
| `401`  | `Unauthenticated.`                                        | Missing or invalid `X-User-Token`                                                               |
| `403`  | `This store cannot access the integrations API.`          | The store does not have the integrations API enabled                                            |
| `403`  | `This token cannot operate on other users' lists.`        | The token does not belong to a store administrator                                              |
| `404`  | `The specified user does not exist in this store.`        | No user matches the identifier sent                                                             |
| `404`  | `The specified publication does not exist in this store.` | No publication matches `content_id` under the given `id_type`                                   |
| `404`  | `Not found`                                               | `{list}` is not a list of the target user, an unknown slug, or a reserved storefront collection |
| `422`  | First validation error                                    | Neither or both user identifiers, missing `content_id`, or an unknown `id_type`                 |
| `429`  | `Too Many Requests`                                       | Rate limit exceeded                                                                             |

An unknown `id_type` returns:

```json
{
  "message": "The selected id type is invalid.",
  "errors": {
    "id_type": ["The selected id type is invalid."]
  }
}
```

---

## Remove a publication from a list {#remove}

Removes the publication from one of the target user's lists.

### Endpoint

```
DELETE /api/v3/lists/{list}/items/{content_id}
```

### Path parameters

| Parameter    | Type   | Description                                                                                                                     |
| ------------ | ------ | ------------------------------------------------------------------------------------------------------------------------------- |
| `list`       | string | The `favorites` slug, or the `id` of one of the user's lists. See [Addressing a list](./lists-v3-overview.md#addressing-a-list) |
| `content_id` | string | The publication identifier, read according to `id_type`                                                                         |

### Query parameters

| Parameter          | Type   | Default    | Description                                                                                                                     |
| ------------------ | ------ | ---------- | ------------------------------------------------------------------------------------------------------------------------------- |
| `user_external_id` | string | -          | Your identifier for the user. Required unless `user_email` is sent                                                              |
| `user_email`       | string | -          | Email of the user. Required unless `user_external_id` is sent                                                                   |
| `id_type`          | string | `internal` | `internal` reads `content_id` as the publica.la id; `external` reads it as one of the publication identifiers (ISBN among them) |

Exactly one of `user_external_id` and `user_email` must be sent.

### Response

**Success (204):**

No body. The response is `204` whether the publication was in the list or not.

### Examples

#### Remove from favorites by ISBN

```bash
curl -X DELETE "https://yourstore.publica.la/api/v3/lists/favorites/items/9781234567890?user_external_id=student-1042&id_type=external" \
  -H "X-User-Token: your-api-token" \
  -H "Accept: application/json"
```

#### Remove from favorites by publica.la id

```bash
curl -X DELETE "https://yourstore.publica.la/api/v3/lists/favorites/items/468166?user_external_id=student-1042" \
  -H "X-User-Token: your-api-token" \
  -H "Accept: application/json"
```

#### Identify the user by email

```bash
curl -X DELETE "https://yourstore.publica.la/api/v3/lists/favorites/items/468166?user_email=student%40example.com" \
  -H "X-User-Token: your-api-token" \
  -H "Accept: application/json"
```

#### Remove from any other list, by id

```bash
curl -X DELETE "https://yourstore.publica.la/api/v3/lists/9f2d4b1e-6c3a-4f58-9b77-1d0a2e5c8b34/items/468166?user_external_id=student-1042" \
  -H "X-User-Token: your-api-token" \
  -H "Accept: application/json"
```

### Errors

| Status | Message                                                   | Cause                                                                                           |
| ------ | --------------------------------------------------------- | ----------------------------------------------------------------------------------------------- |
| `401`  | `Unauthenticated.`                                        | Missing or invalid `X-User-Token`                                                               |
| `403`  | `This store cannot access the integrations API.`          | The store does not have the integrations API enabled                                            |
| `403`  | `This token cannot operate on other users' lists.`        | The token does not belong to a store administrator                                              |
| `404`  | `The specified user does not exist in this store.`        | No user matches the identifier sent                                                             |
| `404`  | `The specified publication does not exist in this store.` | No publication matches `content_id` under the given `id_type`                                   |
| `404`  | `Not found`                                               | `{list}` is not a list of the target user, an unknown slug, or a reserved storefront collection |
| `422`  | First validation error                                    | Neither or both user identifiers, or an unknown `id_type`                                       |
| `429`  | `Too Many Requests`                                       | Rate limit exceeded                                                                             |

---

## Working with favorites {#favorites}

Favorites is the list most integrations write to, and the only one with a slug: address it as `favorites` instead of its `id`, so no lookup is needed.

```
POST   /api/v3/lists/favorites/items
DELETE /api/v3/lists/favorites/items/{content_id}
```

A user who has never favorited anything has no favorites list yet. The endpoints hide that:

- **Add** creates the favorites list on first use, so there is no separate create step. It is not created when the user or the publication does not exist.
- **Remove** returns `204` when the user has no favorites list, the same as removing a publication that is not there.

Custom lists have no slug and are never created by the API. Read their `id` from [List Lists](./lists-v3-list.md) first.

---

## See also

- [Lists API Overview](./lists-v3-overview.md)
- [Get List Items](./lists-v3-get-items.md)
- [List Lists](./lists-v3-list.md)
