> For the complete documentation index, see [llms.txt](https://developer.parvenu.io/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://developer.parvenu.io/enrichments/personalize-with-ai/list-lookup.md).

# List Lookup

Run a prompt template against every row of a Parvenu list. Asynchronous, writes results back into the list.

<mark style="color:green;">`POST`</mark> `/personalize_with_ai_list`

{% hint style="info" %}
This is an **asynchronous** endpoint. It returns a job acknowledgement, not data. Poll `/check_list_status` until the list reports `done`, then fetch the rows with `/download_list`. Costs **0.5 credits** per row processed, the same rate a single [Individual Lookup](/enrichments/personalize-with-ai/individual-lookup.md) costs. Generated copy is written to the `ai_generated_text` column.
{% endhint %}

{% hint style="danger" %}
Your `prompt` **must reference at least one valid column** using `{{column_name}}` syntax. A prompt with no column reference, or one that references a column that does not exist on the list, is rejected with a 400 before any rows are processed (and before any credits are consumed). See Prompt requirements below.
{% endhint %}

Use this to generate an icebreaker or personalized line for every contact in a list in one call, rather than looping over [Individual Lookup](/enrichments/personalize-with-ai/individual-lookup.md) per row.

**Headers**

| Name         | Value              |
| ------------ | ------------------ |
| Content-Type | `application/json` |

**Body**

| Name              | Type   | Description                                                                                                                                                                 |
| ----------------- | ------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `api_key`         | string | Your API Key.                                                                                                                                                               |
| `listname`        | string | Name of the existing Parvenu list to enrich.                                                                                                                                |
| `prompt`          | string | The prompt to run against each row. Must contain at least one `{{column_name}}` reference.                                                                                  |
| `processing_mode` | string | Optional. `blank_only` (default), `all`, or `first_10`. See Processing modes below.                                                                                         |
| `view`            | string | Optional. Which rows of the list to process. `all` (default) processes every contact in the list; `verified` restricts the run to contacts whose email address is verified. |
| `saved_view`      | string | Optional. Name of a saved view on this list. Runs only on the contacts in that view. Don't combine with `view`, `filter_stack` or `search`.                                 |

**Saved views.** To run only on the contacts in a saved view, send its name as `saved_view`. See [List Saved Views](/manage-lists/list-saved-views.md).

**Prompt requirements**

The prompt is a template, not a standalone question. Reference list columns with double curly braces and the API substitutes each row's value before sending it to the model:

```
Write a one-sentence cold email icebreaker for {{person_name}}, {{current_title}} at {{organization_name}}, a company in the {{current_industry}} space.
```

**Which columns can I reference?** Any column on the list: the exact set is the keys returned by [Download List Data](/get-enrichment-results/download-list-data.md) for that list. Common ones include `first_name`, `last_name`, `person_name`, `current_title`, `organization_name`, `current_industry`, `city`, `state`, `country`, `keywords`, and `headcount`, plus the output columns of other enrichments such as `research_with_ai`, `scrapewebsite_with_ai`, `work_experience`, and `company_tech_stack`.

**Richer context from other enrichments.** The model only sees what's in the row, so run other enrichments first and reference their output columns. For example, run [Research with AI](/enrichments/research-with-ai.md) to gather recent funding or product news into `research_with_ai`, then prompt: `Write an icebreaker for {{person_name}} referencing this research: {{research_with_ai}}`.

Two validation failures, both rejected with a 400 and no credits consumed:

* No column reference at all: `No column references found in prompt. Use {{column_name}} format.`
* A column that does not exist on the list: `Invalid column names found`, with the offending names in `invalid_columns`.

**Processing modes**

| Value        | Behaviour                                                                     |
| ------------ | ----------------------------------------------------------------------------- |
| `blank_only` | Default. Only fills rows whose target column is still empty. Cheapest re-run. |
| `all`        | Re-processes and overwrites every row.                                        |
| `first_10`   | Processes only the first 10 fetched rows. Use this to test a prompt cheaply.  |

**View values**

| Value      | Processes                                  |
| ---------- | ------------------------------------------ |
| `all`      | Every row in the list (default).           |
| `verified` | Only rows whose email address is verified. |

**Example**

{% tabs %}
{% tab title="Input" %}

```json
{
  "api_key": "your_api_key",
  "listname": "my_list",
  "prompt": "Write a one-sentence cold email icebreaker for {{person_name}}, {{current_title}} at {{organization_name}}, a company in the {{current_industry}} space.",
  "processing_mode": "first_10",
  "view": "verified"
}
```

{% endtab %}

{% tab title="Output" %}

```json
{
  "status": "queued",
  "job_id": "210",
  "list_name": "my_list",
  "view": "verified",
  "rows_selected": 5,
  "rows_fetched": 5,
  "truncated": false,
  "max_rows": 5000,
  "credits_estimated": 2.5,
  "credits_used": 0,
  "credits_remaining": 4823,
  "message": "Prompt saved/updated successfully with ID: 210. Loaded 5 row(s). Data processing started in background. Only first 10 fetched records will be processed, existing results will be replaced.",
  "success": true
}
```

{% endtab %}

{% tab title="Error" %}

```json
{
  "status": "error",
  "error": {
    "code": "http_error",
    "message": "Failed to start AI personalization due to external API error",
    "detail": "External API error: 400 - {\"detail\":{\"success\":false,\"message\":\"Invalid column names found\",\"invalid_columns\":[\"favorite_color\"]}}"
  },
  "success": false
}
```

{% endtab %}
{% endtabs %}

**Reading the acknowledgement**

Every list-scoped trigger answers with the same envelope, so one piece of client code handles them all.

| Field               | Meaning                                                                                            |
| ------------------- | -------------------------------------------------------------------------------------------------- |
| `status`            | `queued` when the run is accepted. Poll `/check_list_status`; the finished status there is `done`. |
| `job_id`            | Identifier for this run. Always a string. For AI triggers it is the saved prompt id.               |
| `list_name`         | The list being enriched.                                                                           |
| `view`              | Which rows were selected, `all` or `verified`.                                                     |
| `rows_selected`     | How many rows matched your `view` before the page limit was applied.                               |
| `rows_fetched`      | How many rows this run actually picked up. This is the number that gets processed.                 |
| `truncated`         | `true` when the list held more rows than `max_rows`.                                               |
| `max_rows`          | The ceiling a single run will fetch.                                                               |
| `credits_estimated` | What the run is expected to cost, based on the rows it picked up.                                  |

See [Response Format](/getting-started/response-format.md) for the fields every endpoint returns.

{% hint style="info" %}
Test new prompts with `"processing_mode": "first_10"` before running them across a full list. The prompt is saved and reused under the same `job_id`, so a bad prompt run at `all` will overwrite good results.
{% endhint %}

**Retrieving results**

* [Check List Status](/get-enrichment-results/check-list-status.md)
* [Download List Data](/get-enrichment-results/download-list-data.md)
