> For the complete documentation index, see [llms.txt](https://docs.tiny.plus/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.tiny.plus/api/endpoints/lists.md).

# Lists

A list is a collection of companies, contacts or projects that someone has put together, such as the clients to visit this quarter or the guests for an event. A target list is one the firm is working through. [Building Lists](/guides/everyday/building-lists.md) describes them as people use them in tiny+.

Lists have endpoints of their own. They aren't a [record type](/api/endpoints/records.md), so the list filters, search and the generic create, update and delete requests don't apply to them.

| Request                                    | What it does                                                                                       |
| ------------------------------------------ | -------------------------------------------------------------------------------------------------- |
| `GET /v2/lists`                            | [The lists](#the-lists) the token's user made or follows, every list, or the imported ones.        |
| `GET /v2/lists?record_id={id}`             | [The lists a record is on](#the-lists-a-record-is-on), and the ones it could be added to.          |
| `GET /v2/lists?can_add={type}`             | [The lists that take a type of record](#the-lists-that-take-a-type-of-record).                     |
| `GET /v2/lists/{id}`                       | [One list](#get-one-list), with its summary.                                                       |
| `GET /v2/lists/{id}/members`               | [Its members](#members), a page at a time.                                                         |
| `GET /v2/lists/{id}/members/{record_id}`   | [One member](#one-member), and a company's contacts to choose its key contact from.                |
| `GET /v2/lists/{id}/candidates?q=`         | [Records to add](#find-records-to-add), by name.                                                   |
| `POST /v2/lists/{id}/members`              | [Adds records](#add-records).                                                                      |
| `PATCH /v2/lists/{id}/members/{record_id}` | [Sets the comment](#comment-on-a-member) on a member, or a company's [key contact](#key-contacts). |
| `DELETE /v2/lists/{id}/members`            | [Takes records off](#take-records-off).                                                            |
| `POST` and `DELETE /v2/lists/{id}/follow`  | [Follows or unfollows](#follow-a-list) the list.                                                   |
| `POST /v2/lists`                           | [Makes a list](#make-a-list).                                                                      |
| `PATCH /v2/lists/{id}`                     | [Changes a list](#change-a-list).                                                                  |
| `DELETE /v2/lists/{id}`                    | [Deletes a list](#delete-a-list).                                                                  |

Four things differ from the record endpoints:

* **Ids are numbers**, not strings.
* **Text is plain.** Names, descriptions and comments come back as typed, not HTML-escaped.
* **Times are UTC**, as `2026-10-02T02:42:41Z`. A date with no time is `YYYY-MM-DD`.
* **Errors are sentences** written for the person using your app: `{"error": "That list could not be found."}`. See [Errors](#errors).

## Is it there?

[`/me`](/api/endpoints/me.md) lists `lists` in `api_features` when the API has these endpoints, and `list_key_contacts` when it has [key contacts](#key-contacts). `integrations.lists` is `false` on an account that has Lists hidden from its menu.

## Who sees a list

A list is `shared` or `personal`. Everyone in the account can see a shared list, and add to it or take from it. A personal list belongs to the person who made it. For anyone else, an account admin included, every request for it answers `404`, as if it weren't there.

## The lists

<mark style="color:blue;">`GET`</mark> `https://api.tiny.plus/v2/lists`

| Parameter      | Description                                                                                                                                                                  |
| -------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `tab`          | `yours`, the default: the lists the token's user made or follows. `all` is every list they can see. `imports` is the lists that imports made, which the other two leave out. |
| `list_flavour` | Only lists of `companies`, `contacts` or `projects`.                                                                                                                         |
| `q`            | Only lists whose name or description contains this.                                                                                                                          |

Target lists come first, then the rest by name. There is no paging.

```bash
curl "https://api.tiny.plus/v2/lists?tab=all" \
  -H "Authorization: Bearer {{user_access_token}}"
```

```json
{
    "tab": "all",
    "counts": {
        "yours": 4,
        "all": 12,
        "imports": 1
    },
    "records": [
        {
            "id": 164639,
            "name": "Key clients 2027",
            "description": "The clients we most want to keep and grow next year.",
            "list_flavour": "companies",
            "target": true,
            "visibility": "shared",
            "created_user": {
                "id": 191,
                "name": "Maya Lin"
            },
            "mine": true,
            "following": true,
            "member_count": 6,
            "last_added": "2026-10-02T02:42:41Z",
            "created_date": "2026-10-02T02:42:41Z",
            "record_url": "https://crm.tiny.plus/list/164639"
        }
    ]
}
```

`counts` is how many lists each tab holds, whatever `list_flavour` and `q` say.

| Field          | Description                                                                        |
| -------------- | ---------------------------------------------------------------------------------- |
| `list_flavour` | What the list holds: `companies`, `contacts` or `projects`. A list holds one type. |
| `target`       | Whether it's a target list.                                                        |
| `visibility`   | `shared` or `personal`.                                                            |
| `created_user` | Who made it.                                                                       |
| `mine`         | Whether the token's user made it.                                                  |
| `following`    | Whether the token's user follows it.                                               |
| `member_count` | How many records are on it. Deleted and archived records aren't counted.           |
| `last_added`   | When a record was last added, or `null` for an empty list.                         |

## Get one list

<mark style="color:blue;">`GET`</mark> `https://api.tiny.plus/v2/lists/{{id}}`

```bash
curl "https://api.tiny.plus/v2/lists/{{id}}" \
  -H "Authorization: Bearer {{user_access_token}}"
```

```json
{
    "id": 164639,
    "name": "Key clients 2027",
    "description": "The clients we most want to keep and grow next year.",
    "list_flavour": "companies",
    "target": true,
    "visibility": "shared",
    "created_user": {
        "id": 191,
        "name": "Maya Lin"
    },
    "mine": true,
    "following": true,
    "member_count": 6,
    "last_added": "2026-10-02T02:42:41Z",
    "created_date": "2026-10-02T02:42:41Z",
    "record_url": "https://crm.tiny.plus/list/164639",
    "can_change": true,
    "can_edit": true,
    "can_delete": true,
    "plans": true,
    "sorts": ["name", "added", "updated", "next"],
    "summary": {
        "statuses": [
            {
                "value": "active",
                "name": "Current Client",
                "count": 5
            },
            {
                "value": "latent",
                "name": "Past Client",
                "count": 1
            }
        ],
        "plans": {
            "companies": 6,
            "on_plan": 5,
            "overdue": 1,
            "due_soon": 1
        },
        "email": null,
        "fees": null
    }
}
```

| Field                    | Description                                                                                                                                                                                                                                                         |
| ------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `can_change`             | Whether the token's user may add records, take them off and comment on them.                                                                                                                                                                                        |
| `can_edit`, `can_delete` | Whether they may [change](#change-a-list) or [delete](#delete-a-list) the list itself.                                                                                                                                                                              |
| `plans`                  | Whether its members carry [relationship plans](/api/endpoints/relationship-plans.md): a target list of companies, on an account with plans.                                                                                                                         |
| `sorts`                  | The orders [its members](#members) can come in. `next` is only there where `plans` is `true`.                                                                                                                                                                       |
| `summary.statuses`       | How many members are in each status, in the account's status order. `name` is the account's name for the status. A member with no status has `value` `""` and `name` `null`.                                                                                        |
| `summary.plans`          | Where `plans` is `true`: how many companies are on the list, how many have a live plan, and how many of those are overdue or due soon. Otherwise `null`.                                                                                                            |
| `summary.email`          | For a list of contacts: how many there are, and how many have an email address. Otherwise `null`.                                                                                                                                                                   |
| `summary.fees`           | For a list of projects: the fees of its proposals (`pipeline`), and of its won, active, on-hold and completed projects (`confirmed`), as decimal strings. `null` for other lists, and for a person the account [hides fees](/api/endpoints/me.md#permissions) from. |

## Members

<mark style="color:blue;">`GET`</mark> `https://api.tiny.plus/v2/lists/{{id}}/members`

| Parameter        | Description                                                                                                                                                                                                                                                          |
| ---------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `q`              | Only members whose name, or the list's comment on them, contains this. Up to 100 characters.                                                                                                                                                                         |
| `sort`           | `name`, the default. `added` is most recently added first, `updated` most recently changed first, and `next` soonest follow-up first, where the list has `plans`. An order the list doesn't offer falls back to `name`, and the answer's `sort` says which was used. |
| `limit`, `start` | 50 members a page, 200 at most. Pass `next_start` as `start` to get the next page.                                                                                                                                                                                   |
| `ids`            | `1` adds `ids`: the id of every member that matches, in order, whatever the page.                                                                                                                                                                                    |

```bash
curl "https://api.tiny.plus/v2/lists/{{id}}/members?sort=next&limit=1" \
  -H "Authorization: Bearer {{user_access_token}}"
```

```json
{
    "sort": "next",
    "total_records": 6,
    "returned_records": 1,
    "start": 0,
    "next_start": 1,
    "records": [
        {
            "id": 164564,
            "flavour": "companies",
            "name": "Northgate Council",
            "comment": "Framework renewal is due in March.",
            "added": "2026-10-02T02:42:41Z",
            "record_status": "active",
            "record_phase": null,
            "record_status_display": "Current Client",
            "assigned_user": {
                "id": 191,
                "name": "Maya Lin",
                "active": true
            },
            "modified_date": "2026-10-02T02:42:40Z",
            "record_url": "https://crm.tiny.plus/company/164564",
            "show_obscured": false,
            "projects_line": "1 proposed · 2 active projects",
            "key_contact": {
                "id": 164580,
                "name": "Priya Nair",
                "title": "Director of Infrastructure"
            },
            "other_contacts": 1,
            "last_contact": {
                "date": "2026-08-28",
                "touch_type": "meeting"
            },
            "plan": {
                "id": 164621,
                "name": "Key client",
                "status": "overdue",
                "next_due": "2026-09-28",
                "next_step": "Catch-up",
                "paused_until": null,
                "more": 0
            }
        }
    ]
}
```

Every member has these:

| Field                           | Description                                                                           |
| ------------------------------- | ------------------------------------------------------------------------------------- |
| `comment`                       | The list's comment on this member, or `null`.                                         |
| `added`                         | When it was put on the list.                                                          |
| `record_status`, `record_phase` | The record's status, and its phase's id if it has one.                                |
| `record_status_display`         | The phase's name where the record has one, or the account's name for its status.      |
| `assigned_user`                 | Who it's assigned to, or `null`. `active` is `false` for someone who has left.        |
| `show_obscured`                 | `true` for a [confidential record](#confidential-members) the token's user can't see. |

The rest depends on what the list holds.

**Companies**

| Field            | Description                                                                                                                                                                                                                  |
| ---------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `projects_line`  | Its projects in a line, as the list's page in tiny+ writes it, or `null` if it has none.                                                                                                                                     |
| `key_contact`    | Its [key contact](#key-contacts) on this list: the one the list names, or else its first current contact by name. `null` if it has no current contact.                                                                       |
| `other_contacts` | How many more current contacts it has. A confidential contact the token's user can't see isn't counted, or given as the key contact.                                                                                         |
| `last_contact`   | The last follow-up done on one of its relationship plans: `date` and `touch_type`. `null` if there's none.                                                                                                                   |
| `plan`           | Only where the list has `plans`. The company's live plan with the soonest follow-up, or `null`. `status` is `on_track`, `due_soon`, `overdue`, `nothing_booked` or `paused`, and `more` is how many other live plans it has. |

**Contacts**

| Field     | Description                                                             |
| --------- | ----------------------------------------------------------------------- |
| `title`   | Their job title.                                                        |
| `company` | Their company's `id` and `name`, or `null`.                             |
| `email`   | Their email address.                                                    |
| `phone`   | Their direct number, or else their mobile, or else their office number. |

**Projects**

| Field        | Description                                                                                                        |
| ------------ | ------------------------------------------------------------------------------------------------------------------ |
| `client`     | The client's `id` and `name`, or `null`.                                                                           |
| `fee_value`  | The fee, as a decimal string. `null` for a person the account [hides fees](/api/endpoints/me.md#permissions) from. |
| `close_date` | The project's close date.                                                                                          |

### Confidential members

A confidential record the token's user can't see is still a row, so that the rows agree with `member_count`, `summary` and `ids`. It carries only what the list says about it:

```json
{
    "id": 10967,
    "flavour": "projects",
    "name": null,
    "comment": "Ask Sam before calling.",
    "added": "2026-10-04T08:04:41Z",
    "show_obscured": true
}
```

`q` matches such a member by its comment, never by its name.

## One member

<mark style="color:blue;">`GET`</mark> `https://api.tiny.plus/v2/lists/{{id}}/members/{{record_id}}`

One member, as [Members](#members) gives it. On a list of companies it also has `contacts`: the company's current contacts to choose its [key contact](#key-contacts) from, the key contact first, with `key` set.

```bash
curl "https://api.tiny.plus/v2/lists/{{id}}/members/{{record_id}}" \
  -H "Authorization: Bearer {{user_access_token}}"
```

```json
{
    "id": 164564,
    "flavour": "companies",
    "name": "Tasman Health",
    "comment": null,
    "added": "2026-10-02T02:42:41Z",
    "record_status": "active",
    "record_phase": null,
    "record_status_display": "Current Client",
    "assigned_user": {
        "id": 187,
        "name": "Laurence Persimmon",
        "active": true
    },
    "modified_date": "2026-10-02T02:42:39Z",
    "record_url": "https://crm.tiny.plus/company/164564",
    "show_obscured": false,
    "projects_line": null,
    "key_contact": {
        "id": 164579,
        "name": "Ben Okafor",
        "title": "Director of Facilities"
    },
    "other_contacts": 1,
    "last_contact": {
        "date": "2026-09-21",
        "touch_type": "call"
    },
    "plan": {
        "id": 164619,
        "name": "New client: first 90 days",
        "status": "on_track",
        "next_due": "2026-10-19",
        "next_step": "Coffee or lunch",
        "paused_until": null,
        "more": 0
    },
    "contacts": [
        {
            "id": 164579,
            "name": "Ben Okafor",
            "title": "Director of Facilities",
            "key": true
        },
        {
            "id": 164580,
            "name": "Sarah Lindqvist",
            "title": "Capital Projects Lead",
            "key": false
        }
    ]
}
```

A record that isn't on the list answers `404`. A confidential company the token's user can't see comes back [masked](#confidential-members), without `contacts`, and a confidential contact they can't see isn't among them.

## The lists a record is on

<mark style="color:blue;">`GET`</mark> `https://api.tiny.plus/v2/lists?record_id={{record_id}}`

For a company, a contact or a project. `records` is the lists it's on that the token's user can see, target lists first. Each also carries `comment`: that list's comment on this record, as [its members](#members) give it, or `null` when there's none. `can_add` is the lists of its type that it isn't on and they may add it to.

```bash
curl "https://api.tiny.plus/v2/lists?record_id={{record_id}}" \
  -H "Authorization: Bearer {{user_access_token}}"
```

```json
{
    "record_id": 164573,
    "flavour": "contacts",
    "records": [
        {
            "id": 164641,
            "name": "Studio open day guests",
            "description": "Invitations for our studio open day on 20 November.",
            "list_flavour": "contacts",
            "target": false,
            "visibility": "shared",
            "created_user": {
                "id": 191,
                "name": "Maya Lin"
            },
            "mine": false,
            "following": false,
            "member_count": 7,
            "last_added": "2026-10-02T02:42:41Z",
            "created_date": "2026-10-02T02:42:41Z",
            "record_url": "https://crm.tiny.plus/list/164641",
            "comment": "Bringing two colleagues."
        }
    ],
    "can_add": [
        {
            "id": 201,
            "name": "Newsletter Rcpts",
            "target": false,
            "visibility": "shared"
        }
    ]
}
```

`comment` is always there, so an answer without the key comes from an API that doesn't send it yet. To change it, [comment on the member](#comment-on-a-member).

A record the token's user can't see answers `404`, and so does a record of any other type.

## The lists that take a type of record

<mark style="color:blue;">`GET`</mark> `https://api.tiny.plus/v2/lists?can_add=contacts`

The lists the token's user may add `companies`, `contacts` or `projects` to, target lists first, for an "Add to a list" menu. `except` leaves one list out, such as the one the records are already on.

```bash
curl "https://api.tiny.plus/v2/lists?can_add=contacts" \
  -H "Authorization: Bearer {{user_access_token}}"
```

```json
{
    "list_flavour": "contacts",
    "records": [
        {
            "id": 164641,
            "name": "Studio open day guests",
            "target": false,
            "visibility": "shared"
        }
    ]
}
```

## Find records to add

<mark style="color:blue;">`GET`</mark> `https://api.tiny.plus/v2/lists/{{id}}/candidates?q=crest`

Up to 20 records of the list's type whose names contain `q`, by name. `q` needs two characters or more. Confidential records the token's user can't see are left out.

```bash
curl "https://api.tiny.plus/v2/lists/{{id}}/candidates?q=crest" \
  -H "Authorization: Bearer {{user_access_token}}"
```

```json
{
    "records": [
        {
            "id": 164572,
            "name": "Crestwood Water",
            "flavour": "companies",
            "record_status_display": "Current Client",
            "detail": "Parramatta",
            "on_list": true
        }
    ]
}
```

`detail` is a company's town, or the company of a contact or a project. `on_list` says whether the record is on the list already.

## Add records

<mark style="color:green;">`POST`</mark> `https://api.tiny.plus/v2/lists/{{id}}/members`

| Field     | Description                                                                                                                             |
| --------- | --------------------------------------------------------------------------------------------------------------------------------------- |
| `ids`     | Required. The records to add, up to 500: a list of ids, or ids separated by commas.                                                     |
| `restore` | `true` puts a record that was on the list before back with the comment it had. Without it, a record added again starts with no comment. |

```bash
curl -X POST "https://api.tiny.plus/v2/lists/{{id}}/members" \
  -H "Authorization: Bearer {{user_access_token}}" \
  -H "Content-Type: application/json" \
  -d '{
        "ids": [164565, 164568]
      }'
```

```json
{
    "requested": 2,
    "added": 1,
    "member_count": 7
}
```

Only records of the list's own type are added. A record of another type, one that's already on the list, and one the account doesn't have are all skipped, so `added` can be less than `requested`. Adding nothing new is still a `200`.

## Comment on a member

<mark style="color:orange;">`PATCH`</mark> `https://api.tiny.plus/v2/lists/{{id}}/members/{{record_id}}`

```bash
curl -X PATCH "https://api.tiny.plus/v2/lists/{{id}}/members/{{record_id}}" \
  -H "Authorization: Bearer {{user_access_token}}" \
  -H "Content-Type: application/json" \
  -d '{
        "comment": "New asset manager since August. Needs an introduction."
      }'
```

```json
{
    "id": 164572,
    "comment": "New asset manager since August. Needs an introduction."
}
```

An empty `comment` clears it. A record that isn't on the list answers `404`.

## Key contacts

<mark style="color:orange;">`PATCH`</mark> `https://api.tiny.plus/v2/lists/{{id}}/members/{{company_id}}`

On a list of companies, each company has a key contact: the person the list deals with there. Until the list names one, it's the company's first current contact by name. Name another with `key_contact_id`, one of the company's current contacts, which [One member](#one-member) lists:

```bash
curl -X PATCH "https://api.tiny.plus/v2/lists/{{id}}/members/{{company_id}}" \
  -H "Authorization: Bearer {{user_access_token}}" \
  -H "Content-Type: application/json" \
  -d '{
        "key_contact_id": 164579
      }'
```

```json
{
    "id": 164564,
    "key_contact": {
        "id": 164579,
        "name": "Ben Okafor",
        "title": "Director of Facilities"
    }
}
```

`null` goes back to the first by name. The choice belongs to this list, and other lists keep their own. Plans started from a target list in tiny+ are with the key contacts the list gives. `comment` can go in the same request.

A contact who isn't one of the company's current contacts answers `400`, and so does a list that doesn't hold companies. A company that's taken off the list and later added again, without `restore`, starts again from the first by name.

## Take records off

<mark style="color:red;">`DELETE`</mark> `https://api.tiny.plus/v2/lists/{{id}}/members?ids=164565,164568`

Name the records in the query string, up to 500. For one record, `DELETE /v2/lists/{id}/members/{record_id}` does the same.

```bash
curl -X DELETE "https://api.tiny.plus/v2/lists/{{id}}/members?ids=164565,164568" \
  -H "Authorization: Bearer {{user_access_token}}"
```

```json
{
    "requested": 2,
    "removed": 1,
    "member_count": 6
}
```

The records themselves aren't touched. To undo it, [add them](#add-records) again with `restore`.

## Follow a list

<mark style="color:green;">`POST`</mark> `https://api.tiny.plus/v2/lists/{{id}}/follow`

`POST` follows the list for the token's user, and `DELETE` unfollows it. A list they follow is on their `yours` tab.

```bash
curl -X POST "https://api.tiny.plus/v2/lists/{{id}}/follow" \
  -H "Authorization: Bearer {{user_access_token}}"
```

```json
{
    "following": true
}
```

## Make a list

<mark style="color:green;">`POST`</mark> `https://api.tiny.plus/v2/lists`

| Field          | Description                                                                 |
| -------------- | --------------------------------------------------------------------------- |
| `name`         | Required.                                                                   |
| `list_flavour` | Required: `companies`, `contacts` or `projects`. It can't be changed later. |
| `description`  | What the list is for.                                                       |
| `target`       | `true` for a target list. `false` unless you send it.                       |
| `visibility`   | `shared`, unless you send `personal`.                                       |

```bash
curl -X POST "https://api.tiny.plus/v2/lists" \
  -H "Authorization: Bearer {{user_access_token}}" \
  -H "Content-Type: application/json" \
  -d '{
        "name": "Open day guests",
        "description": "Invitations for the studio open day.",
        "list_flavour": "contacts"
      }'
```

The answer is the new list, as [Get one list](#get-one-list) returns it. The token's user follows it.

## Change a list

<mark style="color:orange;">`PATCH`</mark> `https://api.tiny.plus/v2/lists/{{id}}`

Send any of `name`, `description`, `target` and `visibility`. The list needs `can_edit`.

```bash
curl -X PATCH "https://api.tiny.plus/v2/lists/{{id}}" \
  -H "Authorization: Bearer {{user_access_token}}" \
  -H "Content-Type: application/json" \
  -d '{
        "description": "Everyone we are inviting on 20 November.",
        "target": true
      }'
```

The answer is the list, as [Get one list](#get-one-list) returns it.

* A list of more than 100 records can't become a target list. That answers `409`.
* Only the person who made a list can make it `personal`. Anyone else gets a `403`.
* Sending a `list_flavour` other than the list's own answers `400`.

## Delete a list

<mark style="color:red;">`DELETE`</mark> `https://api.tiny.plus/v2/lists/{{id}}`

The list needs `can_delete`. Deleting a list never deletes the records on it.

```bash
curl -X DELETE "https://api.tiny.plus/v2/lists/{{id}}" \
  -H "Authorization: Bearer {{user_access_token}}"
```

```json
{
    "results": true
}
```

## Errors

| Status | When                                                                                                                                                                                                                   |
| ------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `400`  | Something in the request is wrong: `{"error": "Say what the list holds: list_flavour is companies, contacts or projects."}`                                                                                            |
| `403`  | The token's user may not do it: `{"error": "You may not edit this list."}`. Also a [read-only token](/api/concepts/permissions.md#read-only-tokens) trying to change anything: `{"error": "This token is read-only."}` |
| `404`  | There is no such list, or it's someone else's personal list: `{"error": "That list could not be found."}`. Also a record that can't be found, or isn't on the list.                                                    |
| `409`  | The list's state rules it out: `{"error": "A list of more than 100 records can't be a target list."}`                                                                                                                  |
