---
title: Your lists
description: Create, delete, and manage the items on a signed-in user's custom lists.
section: Your data
order: 7
---

# Your lists

You manage a signed-in user's custom lists and their items through the `/v3/sync/lists` endpoints.

> [!REQUIRED]
> Every endpoint on this page needs a credential. GETs need the `read` scope, mutations need the `write` scope. See [Authentication](/dev/authentication).

## Creating a list

`POST /v3/sync/lists` always creates a plain manual list. `is_smart` is `false` on every list you create this way, there's no way to create a rule-based smart list through `/v3`.

| Attribute | Type | Description | Default |
|---|---|---|---|
| `name` | string | List name, trimmed before the 1-200 character length check. Required. | none |
| `description` | string or null | Free text shown with the list. | `null` |
| `privacy` | string or null | One of `private`, `public`, `unlisted`. | `private` |

:::tabs
```bash
curl -X POST "https://flicklist.tv/api/v3/sync/lists" \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"name": "Weekend Watchlist", "privacy": "unlisted"}'
```
```javascript
const res = await fetch('https://flicklist.tv/api/v3/sync/lists', {
  method: 'POST',
  headers: {
    Authorization: `Bearer ${token}`,
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({ name: 'Weekend Watchlist', privacy: 'unlisted' }),
});
const list = await res.json();
```
```python
import requests
r = requests.post(
    "https://flicklist.tv/api/v3/sync/lists",
    headers={"Authorization": f"Bearer {token}"},
    json={"name": "Weekend Watchlist", "privacy": "unlisted"},
)
list_ = r.json()
```
:::

## What you get back

```json
{
  "id": 4821,
  "name": "Weekend Watchlist",
  "slug": "weekend-watchlist",
  "description": null,
  "privacy": "unlisted",
  "is_ranked": false,
  "is_smart": false,
  "tags": [],
  "item_count": 0,
  "likes": 0,
  "created_at": "2026-05-14T02:10:33.000Z",
  "updated_at": "2026-05-14T02:10:33.000Z"
}
```

## Reading lists and items

`GET /v3/sync/lists` returns metadata only, no items, for every list the caller owns. Fetch items per list with `GET /v3/sync/lists/{id}/items`, which returns the full list in list order (this endpoint isn't paginated, unlike the public list-items endpoint on [Public lists & discovery](/dev/lists)).

## Adding and removing items

`POST /v3/sync/lists/{id}/items` and `DELETE /v3/sync/lists/{id}/items` both take a batch of up to 1000 items, resolved through the same [ids object](/dev/ids) contract used everywhere else on `/v3`. Send an `ids` block per item, with `media_type` required whenever `ids` doesn't carry `fldb`.

An item that doesn't resolve to a catalog row lands in `not_found`, it isn't an error and doesn't fail the rest of the batch. On add, an item already on the list counts as `existing`, not `not_found`, so re-running a sync never reads as a failure.

> [!WARNING]
> Smart lists are read-only through the API. `POST` or `DELETE` on a smart list's items rejects the request before processing any item, because a smart list's contents are computed from its rules, not stored directly.

:::tabs
```bash
curl -X POST "https://flicklist.tv/api/v3/sync/lists/4821/items" \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"items": [{"ids": {"tmdb": 550}, "media_type": "movie"}]}'
```
```javascript
const res = await fetch('https://flicklist.tv/api/v3/sync/lists/4821/items', {
  method: 'POST',
  headers: {
    Authorization: `Bearer ${token}`,
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    items: [{ ids: { tmdb: 550 }, media_type: 'movie' }],
  }),
});
const result = await res.json();
```
```python
import requests
r = requests.post(
    "https://flicklist.tv/api/v3/sync/lists/4821/items",
    headers={"Authorization": f"Bearer {token}"},
    json={"items": [{"ids": {"tmdb": 550}, "media_type": "movie"}]},
)
result = r.json()
```
:::

```json
{
  "added": 1,
  "existing": 0,
  "not_found": []
}
```

`DELETE` on the same path matches items by media identity (plus season and episode for episode-level entries), not by an internal list-item id, and returns `removed` plus `not_found` in the same shape.

## Deleting a list

`DELETE /v3/sync/lists/{id}` cascades to the list's items. A list you don't own 404s the same as a list that doesn't exist, so ownership is never leaked.
