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

---
id: eb5f2c66-1101-47a7-a988-84265a669d7e
---

# V1 List API migration guide

> Learn how to migrate from the legacy v1 Contacts Lists API to the latest Lists API

The v1 contact lists API was [sunset on April 30th, 2026](https://developers.hubspot.com/changelog/upcoming-sunset-v1-lists-api). Calls made to the v1 endpoints will no longer function.

Review this guide to understand which endpoints were sunset and to which endpoints you should migrate based on your goal. For complete guidance about using the latest list endpoints, refer to the [lists API guide](/api-reference/latest/crm/lists/guide).

## Contact list ID migration

Contact lists have two list IDs:

* `legacyListId`: the ID used by the v1 lists API.
* `listId`: the ID used by the latest version of the lists API.

As a part of migrating to the latest version of the API, you'll need to update your system to use the `listId` values instead of `legacyListId`. For any given list, the value in each field will be different. However, it's possible that one list's `legacyListId` value matches another list's `listId` value, so ensure you retrieve all list IDs and compare them carefully to prevent list mapping issues.

To retrieve the `legacyListId` and `listId` values of each list:

1. Use the [ID mapping endpoint](#use-the-list-id-mapping-endpoint) to get the new list IDs for all of the lists in your account.
2. To prevent data loss in the event of a mistake during migration, store the new list IDs alongside the v1 list IDs.
3. Once all list IDs have been fetched and stored, migrate to using the List APIs with the new list IDs.
4. When you’ve fully switched over to using the latest version of the lists API, you can remove the stored v1 list IDs and drop any references to v1 list ID information.

### Use the list ID mapping endpoint

To fetch mappings one at a time, make a `GET` request to `/crm/lists/2026-03/idmapping?legacyListId={legacyListId}` with the v1 list ID in the `legacyListID` parameter.

Your response will look like:

```json theme={null}
{
  "listId": "61",
  "legacyListId": "64"
}
```

To fetch multiple ID mappings in one batch, make a `POST` request to `/crm/lists/2026-03/idmapping` and include the `legacyListID` values within an array, limited to 10,000 entries.

For example, your request would look like:

```json theme={null}
["64", "33", "22566"]
```

The response would look like:

```json theme={null}
{
  "missingLegacyListIds": ["22566"],
  "legacyListIdsToIdsMapping": [
    {
      "listId": "61",
      "legacyListId": "64"
    },
    {
      "listId": "38",
      "legacyListId": "33"
    }
  ]
}
```

You can now use the `listId` values to refer to lists in the latest list endpoints. The latest version of the lists API is the source of truth, so if a mapping does not exist via the latest API (indicated by the `missingLegacyListIds` field), it means the list no longer exists.

## Impacted endpoints

The following endpoints will return a 404 error as of April 30, 2026.

Create, update, and delete contact list endpoints:

* [Create a new contact list](#create-lists): `POST` `/contacts/v1/lists`
* [Update contact lists](#update-lists): `POST` `/contacts/v1/lists/{legacyListId}`
* [Add contacts to a list](#add-or-remove-records-in-a-list): `POST` `/contacts/v1/lists/{legacyListId}/add`
* [Remove contacts from a list](#add-or-remove-records-in-a-list): `POST` `/contacts/v1/lists/{legacyListId}/remove`
* [Delete a contact list](#delete-lists): `DELETE` `/contacts/v1/lists/{legacyListId}`

Retrieve contact list endpoints:

* Get all contact lists: `GET` `/contacts/v1/lists`
* [Get a contact list by ID](#get-lists-by-list-id): `GET` `/contacts/v1/lists/{legacyListId}`
* [Get a group of contact lists](#get-lists-by-list-id): `GET` `/contacts/v1/lists/batch`
* [Get static contact lists](#get-all-static-lists): `GET` `/contacts/v1/lists/static`
* [Get dynamic (active) contact lists](#get-all-active-lists): `GET` `/contacts/v1/lists/dynamic`
* Get list historical size and edit dates: `GET` `/v1/lists/{legacyListId}/sizeAndEditsHistory/between`. At this time, there is no equivalent endpoint.

Retrieve contacts in a list endpoints:

* [Get contacts in a list](#get-all-members-of-a-list): `GET` `/contacts/v1/lists/{legacyListId}/contacts/all`
* [Get recently added contacts from a list](#get-recent-list-members): `GET` `/contacts/v1/lists/{legacyListId}/contacts/recent`

Retrieve contacts with list memberships endpoints:

* [Get recently created contacts with list memberships](#retrieve-records-with-list-memberships): `GET` `/contacts/v1/lists/all/contacts/recent`
* [Get recently updated contacts with list memberships](#retrieve-records-with-list-memberships): `GET` `/contacts/v1/lists/recently_updated/contacts/recent`
* [Get all contacts with list memberships](#retrieve-records-with-list-memberships): `GET` `/contacts/v1/lists/all/contacts/all`

The following endpoints still function, but as of April 30, 2026, no longer return list memberships:

* Get a contact by visitor ID: `GET` `/contacts/v1/contact/vid/{vid}/profile`
* Get a batch of contacts by visitor ID: `GET` `/contacts/v1/contact/vids/batch`
* Get a contact by email address: `GET` `/contacts/v1/contact/email/{contact_email}/profile`
* Get a batch of contacts by email address: `GET` `/contacts/v1/contact/emails/batch`
* Get a contact by user token: `GET` `/contacts/v1/contact/utk/{contact_utk}/profile`
* Get a batch of contacts by user token: `GET` `/contacts/v1/contact/byUtk/batch`

## Migrate from v1 to latest list endpoints

If you were previously using any of the v1 list endpoints, you can migrate to the equivalent endpoints, detailed in the sections below.

<Warning>
  In the latest endpoint request URLs and request bodies, you must use the new list
  ID (`listId`). Using a v1 list ID (`legacyListId`) for these endpoints may
  result in updating or deleting the wrong list. Learn more about [list ID
  migration](#contact-list-id-migration).
</Warning>

### Create lists

If you’re using `POST` `/contacts/v1/lists` to create lists, migrate to `POST` `/crm/lists/2026-03`. In the request body, you must include the following fields: `name`, `objectTypeId`, and `processingType`. Refer to the [lists API guide](/api-reference/latest/crm/lists/guide) for more information on other fields.

You can create lists for objects other than contacts with the latest API, but if your goal is to create a list of contacts, your `objectTypeId` value must be `0-1`.

For example:

```json theme={null}
{
  "name": "My static list",
  "objectTypeId": "0-1",
  "processingType": "MANUAL"
}
```

When you create a list with the latest endpoint, the `listId` is returned, which should be the list ID used moving forward.

### Update lists

If you’re using `POST` `/contacts/v1/lists/{legacyListId}` to update a list, migrate to the following endpoints depending on your goal.

To update an active list’s filters, migrate to `PUT` `/crm/lists/2026-03/{listId}/update-list-filters`. In your request, include the `filterBranch` parameter to your request. Learn more about [setting up filter branches](/api-reference/latest/crm/lists/list-filters).

To update a list’s name, migrate to `PUT` `/crm/lists/2026-03/{listId}/update-list-name`. In your request URL, include the `listId` of the list and the updated `listName`. For example: `crm/lists/2026-03/12345/update-list-name?listName=New%20list%20name`.

### Add or remove records in a list

If you’re updating contact list membership using `POST` `/contacts/v1/lists/{legacyListId}/add` and `POST` `/contacts/v1/lists/{legacyListId}/remove`, migrate to the following endpoints depending on your goal. You can only manually add or remove records in a static list.

* To add records to a list, migrate to `PUT` `/crm/lists/2026-03/{listId}/memberships/add`. Include an array with the `id` values of records to add.
* To remove records from a list, migrate to `PUT` `/crm/lists/2026-03/{listId}/memberships/remove`. Include an array with the `id` values of records to remove.

```json theme={null}
["1234", "5678", "9101"]
```

To both add and remove records from a list, migrate to `PUT` `/crm/lists/2026-03/{listId}/memberships/add-and-remove`. Include the `recordsToRemove` array with `id` values of records to remove from the list and the `recordsToAdd` array with `id` values of records to add to the list.

```json theme={null}
{
  "recordIdsToRemove": [654, "321"],
  "recordIdsToAdd": [123, 456, 789]
}
```

### Delete lists

If you’re using `DELETE` `/contacts/v1/lists/{legacyListId}` to delete a list, migrate to `DELETE` `/crm/lists/2026-03/{listId}`.

### Get all static lists

If you’re using `GET` `/contacts/v1/lists/static` to get static lists, migrate to `POST` `/crm/lists/2026-03/search`. In the request body, include `SNAPSHOT` and `MANUAL` in the `processingTypes` array. Include an `additionalProperties` array to request that certain list properties are returned.

```json theme={null}
{
  "offset": 0,
  "count": 100,
  "processingTypes": ["MANUAL", "SNAPSHOT"]
}
```

### Get all active lists

If you’re using `GET` `/contacts/v1/lists/dynamic` to get active lists, migrate to `POST` `/crm/lists/2026-03/search`. In the request body, include `DYNAMIC` in the `processingTypes` array. Include an `additionalProperties` array to request that certain list properties are returned.

```json theme={null}
{
  "offset": 0,
  "count": 100,
  "processingTypes": ["DYNAMIC"]
}
```

### Get lists by list ID

If you’re using `GET` `/contacts/v1/lists/{legacyListId}` to retrieve individual lists by ID, migrate to `GET` `/crm/lists/2026-03/{listId}`.

If you’re using `GET` `/contacts/v1/lists/batch` to retrieve multiple lists by ID, migrate to `GET` `/crm/lists/2026-03`. In the request URL, include `listId` values. To include filter branches in the response, set the `includeListFilters` query param to `true`. For example, your request URL would look like: `/crm/lists/2026-03?includeFilters=true&listIds=42&listIds=51`.

You can also use the [search API](/api-reference/latest/crm/search-the-crm) to filter the lists further, such as by `processingType` or custom list properties.

### Get all members of a list

If you’re using `GET` `/contacts/v1/lists/{legacyListId}/contacts/all` to retrieve contacts in a list, migrate to `GET` `/crm/lists/2026-03/{listId}/memberships`. Records will be returned in order based on their `id` values.

Your response will look similar to the following:

```json theme={null}
{
  "results": [
    {
      "recordId": "13161075754",
      "membershipTimestamp": "2025-05-22T16:33:17.864Z"
    },
    {
      "recordId": "13242183272",
      "membershipTimestamp": "2025-05-22T16:33:17.864Z"
    },
    {
      "recordId": "14559658632",
      "membershipTimestamp": "2025-05-22T16:33:17.864Z"
    },
    {
      "recordId": "20903185697",
      "membershipTimestamp": "2025-05-22T16:33:17.864Z"
    },
    {
      "recordId": "20903217801",
      "membershipTimestamp": "2025-05-22T16:33:17.864Z"
    },
    {
      "recordId": "20903639452",
      "membershipTimestamp": "2025-05-22T16:33:17.864Z"
    },
    {
      "recordId": "20903662261",
      "membershipTimestamp": "2025-05-22T16:33:17.864Z"
    },
    {
      "recordId": "20903719953",
      "membershipTimestamp": "2025-05-22T16:33:17.864Z"
    },
    {
      "recordId": "20903752823",
      "membershipTimestamp": "2025-05-22T16:33:17.864Z"
    },
    {
      "recordId": "20903842625",
      "membershipTimestamp": "2025-05-22T16:33:17.864Z"
    }
  ],
  "total": 10
}
```

### Get recent list members

If you’re using `GET` `/contacts/v1/lists/{legacyListId}/contacts/recent` to retrieve contacts recently added to a list, migrate to `GET` `/crm/lists/2026-03/{listId}/memberships/join-order`. Records will be returned with their `id` values in the order in which they were added to the list.

Your response will look similar to the following:

```json theme={null}
{
  "results": [
    {
      "recordId": "41720992115",
      "membershipTimestamp": "2025-07-28T13:42:08.595Z"
    },
    {
      "recordId": "79129291921",
      "membershipTimestamp": "2025-01-21T18:06:02.387Z"
    },
    {
      "recordId": "33451",
      "membershipTimestamp": "2023-08-31T16:24:37.296Z"
    }
  ],
  "total": 2
}
```

### Retrieve records with list memberships

If you’re using `GET` `/contacts/v1/lists/all/contacts/all`, `GET` `/contacts/v1/lists/recently_updated/contacts/recent`, or `GET` `/contacts/v1/lists/all/contacts/recent` to retrieve contacts with list memberships, you’ll need to migrate to the latest object and search endpoints. This is because migration for retrieving contacts and their memberships requires two calls: one to retrieve the records, then another to retrieve their list memberships.

First, make a `POST` request to `/crm/objects/2026-03/{objectTypeId}/search` with the object for which you want to search records (i.e. `0-1` for contacts). You can add filters to specify the records you want.

* To retrieve recently created records, filter by `createdate`.
* To retrieve recently updated records, filter by `lastmodifieddate`.

You can add properties to retrieve more details about the records as needed.

For example, to search for contacts edited after May 31, 2025:

```json theme={null}
{
  "properties": ["firstname", "lastname", "email", "hs_object_id", "createdate", "lastmodifieddate"],
  "filterGroups": [
    {
      "filters": [
        {
          "propertyName": "lastmodifieddate",
          "operator": "GT",
          "value": "2025-05-31"
        }
      ]
    }
  ]
}
```

Next, use the object endpoint to retrieve the membership details for the contacts individually or in bulk. From your search request, use record `id` values to retrieve list membership details.

To retrieve an individual record's memberships, make a `GET` request to `/crm/lists/2026-03/records/{objectTypeId}/{recordId}/memberships`. For example, to retrieve a contact’s memberships, your request URL would look like `/crm/lists/2026-03/records/0-1/1234567/memberships`.

Your response will look like:

```json theme={null}
{
  "results": [
    {
      "listId": "76",
      "listVersion": 1,
      "isPublicList": true,
      "firstAddedTimestamp": "2025-07-28T13:42:08.595Z",
      "lastAddedTimestamp": "2025-07-28T13:42:08.595Z"
    },
    {
      "listId": "78",
      "listVersion": 1,
      "isPublicList": true,
      "firstAddedTimestamp": "2025-07-28T13:42:08.595Z",
      "lastAddedTimestamp": "2025-07-28T13:42:08.595Z"
    },
    {
      "listId": "493",
      "listVersion": 1,
      "isPublicList": false,
      "firstAddedTimestamp": "2024-07-23T19:40:36.192Z",
      "lastAddedTimestamp": "2024-07-23T19:40:36.192Z"
    },
    {
      "listId": "541",
      "listVersion": 1,
      "isPublicList": true,
      "firstAddedTimestamp": "2025-04-21T14:01:43.475Z",
      "lastAddedTimestamp": "2025-04-21T14:01:43.475Z"
    },
    {
      "listId": "492",
      "listVersion": 1,
      "isPublicList": false,
      "firstAddedTimestamp": "2024-07-23T19:36:11.890Z",
      "lastAddedTimestamp": "2024-07-23T19:36:11.890Z"
    }
  ]
}
```

To retrieve multiple records' memberships, make a `POST` request to `/crm/lists/2026-03/records/memberships/batch/read`. In the request, include the `objectTypeId` [value](/guides/crm/understanding-the-crm#object-type-ids) of the object for which you're retrieving records (e.g.,  `0-1` for contacts) and the `id` values for the records.

For example, to retrieve memberships for contacts `12345` and `67890`, your request would look like:

```json theme={null}
{
  "inputs": [
    {
      "objectTypeId": "0-1",
      "recordId": "12345"
    },
    {
      "objectTypeId": "0-1",
      "recordId": "67890"
    }
  ]
}
```
