---
title: "Create Batch Add to List Job"
method: POST
path: "/v1/lists/batch-add-to-list-jobs"
tags: ["Lists", "v1"]
---

# Create Batch Add to List Job

`POST /v1/lists/batch-add-to-list-jobs`

## Request

- Base URL: `https://api.leadfeeder.com`
- URL: `https://api.leadfeeder.com/v1/lists/batch-add-to-list-jobs`
- Auth: one of:
  - API key in header `X-Api-Key`
  - OAuth 2
    - Authorization code: `https://api.leadfeeder.com/v1/oauth/authorize`
    - Token URL: `https://api.leadfeeder.com/v1/oauth/token` scopes: `lists:write`

Schedule an asynchronous job that adds members to a single list. The target list is identified by `data.attributes.list_id` in the request body; its prefix (`company_` or `contact_`) determines whether `company` or `contact` references are accepted. You need permission to change the list's members, and it can't be a read-only list, such as a revealed, CRM or custom feed list. The members are supplied either as an explicit `data.attributes.items` array (up to 100 items per request), or — for company lists only — as a `data.attributes.advanced_search` selection that is resolved into companies (up to 100,000) when the job runs. A list holds at most 1,000,000 members. To remove members, use `POST /v1/lists/batch-remove-from-list-jobs` — adding and removing are separate jobs.

Returns `202 Accepted` with a job handle. Poll `GET /v1/lists/batch-add-to-list-jobs/{job_id}` to observe progress and the outcome: per-item `results` plus `summary` counts for `items` jobs, `summary` counts only for jobs created from a search selection.

Credit Note: Adding members to a list does not consume credits.

:::info
Requires the `lists:write` OAuth2 scope.
:::

## Query parameters

- `account_id` string, required

## Request body

- object: Request body for creating a batch add-to-list job. The target list is identified by `list_id` inside `data.attributes` — the list ID's prefix (`company_` or `contact_`) determines which kind of references are valid. Supplying references whose type does not match the list scope yields `422 invalid_parameter` (scope mismatch). The members are supplied either as an explicit `items` array, or — for company lists only — as an `advanced_search` selection that is resolved into companies when the job runs. Exactly one way of supplying the members must be used.
  - `data` object, required
    - `attributes` union, required
      - object
        - `advanced_search` object: Add every company matching an advanced search to the list, instead of listing companies one by one in `items`. Use the same `filters`, `sort` and `page` you would when browsing companies. When the job runs, it takes the matches in `sort` order up to `page.size` (at most 100,000, which is also the default), then drops the `excluded_company_ids`, so fewer than `page.size` can be added. The search checks the filters and the sort only then: a filter tree or sort it rejects fails the job with the search's own error, such as `invalid_filters`. This is only available for company lists — it can't be used on a contact list or together with `items`. The outcome is reported as `summary` counts rather than a per-company `results` list; any companies that couldn't be added are counted under `not_found`. If the matches would take the list past 1,000,000 members, the job fails with `list_capacity_exceeded` and adds none of them. Matches that are already on the list count toward this limit.
          - `excluded_company_ids` string[]: Company IDs to remove from the matched set (for example, rows the user deselected). Removed after the `page.size` limit is applied, so the final selection may be smaller than `page.size`.
          - `filters` object, required: Recursive filter tree applied to the company population. The root is always a `group` whose `items` are either individual filters or further `group` nodes (combined with `and`/`or`). The tree holds at most 50 filters and groups, the root included, and at most 5 levels of groups.
            - `items` CompaniesAdvancedSearchFilterItem[], required: Nested filter conditions or sub-groups. Each item is either a `filter` or a nested `group`. An empty list matches every company.
              - …
            - `operator` 'and' | 'or', required: The logical operator combining the items.
            - `type` 'group', required: Indicates this is the root filter group.
          - `page` object: Bounds how many of the matching companies are selected.
            - `size` integer: Maximum number of matching companies to select, taken in `sort` order. Omit to select every match, up to the endpoint's per-job maximum.
          - `sort` object: Ordering applied to the matching companies. Omit to use the default ordering.
            - `direction` 'asc' | 'desc': Sort direction. Defaults to `asc`.
            - `field` string: Comma-separated list of company attributes to sort by, applied in order (e.g. `employee_count,name`). Allowed values: `relevance`, `name`, `employee_count`, `revenue`, `founded_year`. Unknown values are rejected with `invalid_parameter`.
        - `items` object[], required: The company or contact references to add to the list. A maximum of 100 items may be supplied, repeats included. Every item's `type` must match the target list's kind (company list → `company`, contact list → `contact`). An item sent more than once is added and reported once. The IDs are checked when the job runs, so an unknown ID is reported as `not_found` rather than rejected. Mutually exclusive with `advanced_search`.
          - `id` string, required: The Dealfront entity ID.
          - `type` 'company' | 'contact', required: The entity type of the reference — must match the target list's kind.
        - `list_id` string, required: The scope-prefixed target list identifier (e.g. `company_123` or `contact_456`). Its prefix determines which kind of references may appear in `items`. You need permission to change its members, and it can't be a read-only list, such as a revealed, CRM or custom feed list.
      - object
        - `advanced_search` object, required: Add every company matching an advanced search to the list, instead of listing companies one by one in `items`. Use the same `filters`, `sort` and `page` you would when browsing companies. When the job runs, it takes the matches in `sort` order up to `page.size` (at most 100,000, which is also the default), then drops the `excluded_company_ids`, so fewer than `page.size` can be added. The search checks the filters and the sort only then: a filter tree or sort it rejects fails the job with the search's own error, such as `invalid_filters`. This is only available for company lists — it can't be used on a contact list or together with `items`. The outcome is reported as `summary` counts rather than a per-company `results` list; any companies that couldn't be added are counted under `not_found`. If the matches would take the list past 1,000,000 members, the job fails with `list_capacity_exceeded` and adds none of them. Matches that are already on the list count toward this limit.
          - `excluded_company_ids` string[]: Company IDs to remove from the matched set (for example, rows the user deselected). Removed after the `page.size` limit is applied, so the final selection may be smaller than `page.size`.
          - `filters` object, required: Recursive filter tree applied to the company population. The root is always a `group` whose `items` are either individual filters or further `group` nodes (combined with `and`/`or`). The tree holds at most 50 filters and groups, the root included, and at most 5 levels of groups.
            - `items` CompaniesAdvancedSearchFilterItem[], required: Nested filter conditions or sub-groups. Each item is either a `filter` or a nested `group`. An empty list matches every company.
              - …
            - `operator` 'and' | 'or', required: The logical operator combining the items.
            - `type` 'group', required: Indicates this is the root filter group.
          - `page` object: Bounds how many of the matching companies are selected.
            - `size` integer: Maximum number of matching companies to select, taken in `sort` order. Omit to select every match, up to the endpoint's per-job maximum.
          - `sort` object: Ordering applied to the matching companies. Omit to use the default ordering.
            - `direction` 'asc' | 'desc': Sort direction. Defaults to `asc`.
            - `field` string: Comma-separated list of company attributes to sort by, applied in order (e.g. `employee_count,name`). Allowed values: `relevance`, `name`, `employee_count`, `revenue`, `founded_year`. Unknown values are rejected with `invalid_parameter`.
        - `items` object[]: The company or contact references to add to the list. A maximum of 100 items may be supplied, repeats included. Every item's `type` must match the target list's kind (company list → `company`, contact list → `contact`). An item sent more than once is added and reported once. The IDs are checked when the job runs, so an unknown ID is reported as `not_found` rather than rejected. Mutually exclusive with `advanced_search`.
          - `id` string, required: The Dealfront entity ID.
          - `type` 'company' | 'contact', required: The entity type of the reference — must match the target list's kind.
        - `list_id` string, required: The scope-prefixed target list identifier (e.g. `company_123` or `contact_456`). Its prefix determines which kind of references may appear in `items`. You need permission to change its members, and it can't be a read-only list, such as a revealed, CRM or custom feed list.
    - `type` string: The job resource type. Optional — the operation is fixed by the endpoint, so a value supplied here is ignored.

## Response `202`

Batch add-to-list job accepted and enqueued

- object
  - `data` BatchAddToListJobV1, required
    - `attributes` object, required
      - `completed_at` string, date-time, nullable: When the job finished. Present only once the job has reached `completed` or `failed`.
      - `configuration` union, required: Echoed request configuration. Present at every status, from the moment the job is created. Carries the `items` array (each repeated item once) or the search selection the job was created with — exactly one of the two.
        - object
          - `advanced_search` object: The advanced-search selection supplied in the originating request.
            - `excluded_company_ids` string[]: Company IDs to remove from the matched set (for example, rows the user deselected). Removed after the `page.size` limit is applied, so the final selection may be smaller than `page.size`.
            - `filters` object, required: Recursive filter tree applied to the company population. The root is always a `group` whose `items` are either individual filters or further `group` nodes (combined with `and`/`or`). The tree holds at most 50 filters and groups, the root included, and at most 5 levels of groups.
              - …
            - `page` object: Bounds how many of the matching companies are selected.
              - …
            - `sort` object: Ordering applied to the matching companies. Omit to use the default ordering.
              - …
          - `items` object[], required: The references supplied in the originating request, each repeated item once.
            - `id` string, required: The Dealfront entity ID.
            - `type` 'company' | 'contact', required: The entity type (e.g. `company` or `contact`).
          - `list_id` string, required: The scope-prefixed list identifier the job operates on (e.g. `company_123` or `contact_456`).
        - object
          - `advanced_search` object, required: The advanced-search selection supplied in the originating request.
            - `excluded_company_ids` string[]: Company IDs to remove from the matched set (for example, rows the user deselected). Removed after the `page.size` limit is applied, so the final selection may be smaller than `page.size`.
            - `filters` object, required: Recursive filter tree applied to the company population. The root is always a `group` whose `items` are either individual filters or further `group` nodes (combined with `and`/`or`). The tree holds at most 50 filters and groups, the root included, and at most 5 levels of groups.
              - …
            - `page` object: Bounds how many of the matching companies are selected.
              - …
            - `sort` object: Ordering applied to the matching companies. Omit to use the default ordering.
              - …
          - `items` object[]: The references supplied in the originating request, each repeated item once.
            - `id` string, required: The Dealfront entity ID.
            - `type` 'company' | 'contact', required: The entity type (e.g. `company` or `contact`).
          - `list_id` string, required: The scope-prefixed list identifier the job operates on (e.g. `company_123` or `contact_456`).
      - `created_at` string, date-time, required: When the job was created.
      - `errors` object[]: Present only when `status` is `failed`, with one error: - `list_capacity_exceeded`, "Applying these operations would exceed the maximum list size": the members would take the list past 1,000,000. - `list_not_found`, "The list could not be found": the list no longer exists when the job runs. - `list_access_denied`, "The list is no longer accessible": you can no longer change the list when the job runs, for example because you lost access to it. - `job_exhausted_retries`, "Membership update failed after exhausting retries": temporary errors persisted. Create the job again. - `job_failed`, "Membership update could not be applied": any other error. - For a job created from a search selection, the search's own code and title, such as `invalid_filters` when it rejects the filter tree, `invalid_parameter` when it rejects the sort, `unprocessable_entity` when a list in the filters no longer exists, or `server_timeout` when it takes too long. A failed job reports no counts. Members it added before failing stay on the list.
        - `code` string, required: Machine-readable error code
        - `title` string, required: Human-readable error description
      - `results` object[]: Per-item outcome of the add job, in request order, each repeated item once. Present only when `status` is `completed` and the job was created with an explicit `items` array — a job created from a search selection reports `summary` counts only. Items that exist but couldn't be added are left out and counted in `summary.failed_count`.
        - `id` string, required: The Dealfront company or contact ID that was processed.
        - `status` 'added' | 'already_present' | 'not_found', required: What the job did with this item.
        - `type` 'company' | 'contact', required: The kind of entity this result item refers to.
      - `status` 'running' | 'completed' | 'failed', required: Current status of the job
      - `summary` object: Counts of items by outcome, plus the list size before and after the job applied. Present only when `status` is `completed`.
        - `added` integer: Number of members added. For a job created from a search selection, the matches added.
        - `already_present` integer: Number of members already in the list (add no-op). For a job created from a search selection, the matches that were already on the list.
        - `failed_count` integer: Total number of items that exist but couldn't be added, which `results` leaves out. Always 0 for a job created from a search selection, which counts them in `not_found`.
        - `list_size_after` integer: Number of members on the list after the job applied, counting every member.
        - `list_size_before` integer: Number of members on the list when the job was created, not counting the members whose company or contact record no longer exists.
        - `not_found` integer: Number of referenced entities that could not be found, including references whose ID isn't a number. For a job created from a search selection, matches that could not be added are counted here.
        - `scope_mismatch` integer: Number of references whose type did not match the list scope. Always 0: such a reference is rejected when the job is created.
    - `id` string, required: Unique job identifier
    - `type` string, required
  - `meta` object, required
    - `request_id` string, required: A unique identifier assigned to each API request for end-to-end traceability.

## Other responses

- `400`: Malformed request envelope — the body is missing the required `data.attributes` object.
- `401`: Unauthorized. The request was rejected because the credentials are missing, invalid, expired, or have been revoked. The client must re-authenticate before retrying. Clients can differentiate via the `code` value of the first item in `errors`.
- `403`: Forbidden: the credentials are valid but don't allow this request. The gateway refuses a user without API access on the account, a plan without API access, a token without the `lists:write` scope, and a missing or foreign `account_id`. The request is also refused when you may not read the list, when you may not change its members (for example, because it is shared with you for viewing only), or when it is a read-only list, such as a revealed, CRM or custom feed list.
- `404`: List not found in this account. Returned synchronously, before any job is created.
- `422`: A body that isn't valid JSON, or a well-formed envelope that fails domain validation — scope mismatch (item `type` does not match the list's kind), empty `items`, more than 100 items, both `items` and `advanced_search` supplied, an `advanced_search` selection on a contact list or without `filters`, a list ID, item or selection field that breaks another rule (the title says which), or per-list capacity exceeded (adding these members would push the list beyond its maximum size of 1,000,000 members; fail-fast, no changes applied). The synchronous capacity check applies to `items` jobs only — a search selection's member count is unknown until the search is resolved, so its capacity limit is enforced during execution and exceeding it fails the job with `list_capacity_exceeded`.
- `429`: Too many requests. Either the per-second rate limit or the monthly quota configured for the API key / OAuth application has been exceeded. Clients can differentiate via the `code` value of the first item in `errors`.
- `500`: Internal server error
- `504`: Server timeout

## Changes

> 46 revisions in range; 1 not diffed.

- **2026-10-30** `8e37aaf0ccad`: 1 info
  - removed the `scope_mismatch` enum value from the `data/attributes/results/items/status` response property for the response status `202`
- **2026-10-28** `1344fb600ac2`: 2 breaking
  - the `data/attributes/configuration/advanced_search/allOf[subschema #1]/filters/items` response property's minItems was decreased from `1` to `0` for the response status `202`
  - the `data/attributes/configuration/advanced_search/allOf[subschema #1]/filters/items/items/oneOf[subschema #37: Group]/items` response property's minItems was decreased from `1` to `0` for the response status `202`
- **2026-10-06** `69e0c94ac1fd`: 2 info
  - added the new optional request property `data/attributes/advanced_search/allOf[subschema #1]/filters/items/items/oneOf[subschema #5: Geo Filter]/label`
  - added the optional property `data/attributes/configuration/advanced_search/allOf[subschema #1]/filters/items/items/oneOf[subschema #5: Geo Filter]/label` to the response with the `202` status
- …earlier changes not shown

[Operation history](https://skmtc.dev/leadfeeder/apis/leadfeeder-public-api/changes/v1/lists/batch-add-to-list-jobs/post.md)

---

[API](https://skmtc.dev/leadfeeder/apis/leadfeeder-public-api.md) - [All operations](https://skmtc.dev/leadfeeder/apis/leadfeeder-public-api/llms.txt) - [OpenAPI document](https://skmtc.dev/leadfeeder/apis/leadfeeder-public-api/revisions/686d4e39eb05?raw)
