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

# FindAll Migration Guide

> Guide for migrating from V0 to V1 FindAll API

<div className="sr-only" aria-hidden="false">
  For AI agents: a documentation index is available at [https://docs.parallel.ai/llms.txt](https://docs.parallel.ai/llms.txt). The full text of all docs is at [https://docs.parallel.ai/llms-full.txt](https://docs.parallel.ai/llms-full.txt). You may also fetch any page as Markdown by appending `.md` to its URL or sending `Accept: text/markdown`.
</div>

<Note>
  **Timeline**: V1 is now the default for the FindAll API. Requests no longer need the `parallel-beta: "findall-2025-09-15"` header — requests without it use V1. The header is still accepted for backwards compatibility but no longer changes behavior. Existing V0 runs remain retrievable by their original run IDs.
</Note>

## Why Migrate to V1?

V1 delivers significant improvements across pricing, performance, and capabilities:

1. **[Pay-per-Match Pricing](/findall-api/core-concepts/findall-generator-pricing)**: Charges based on matches found, not candidates evaluated

2. **[Task-Powered Enrichments](/findall-api/features/findall-enrich)**: Flexible enrichments via Task API with expanded processor options

3. **Enhanced Capabilities:**
   * [Extend](/findall-api/features/findall-extend) and [Cancel](/findall-api/features/findall-cancel) endpoints, plus the [Preview](/findall-api/features/findall-preview) generator
   * [Real-time streaming](/findall-api/features/findall-sse) with incremental updates
   * [Exclude candidates](/findall-api/core-concepts/findall-candidates) from evaluation
   * Match conditions return both `value` and `is_matched` boolean
   * Explicit `match_limit` range from 5 to 1,000

4. **Better Performance**: Improved latency and match quality across all stages

<Warning>
  **Breaking Changes**: V0 and V1 request and response contracts are not interchangeable. Existing V0 run IDs remain retrievable through the status endpoint, but V1-only schemas and features such as `/result`, `/extend`, and `/enrich` do not apply to those runs. Parameter names, response schemas, and pricing have changed.
</Warning>

## Key Differences

### Request Structure

V0 used a nested `findall_spec` object. V1 flattens this structure:

| **Concept**         | **V0 API**                               | **V1 API**                     |
| ------------------- | ---------------------------------------- | ------------------------------ |
| **Search Goal**     | `query`                                  | `objective`                    |
| **Entity Type**     | `findall_spec.name`                      | `entity_type`                  |
| **Filter Criteria** | `findall_spec.columns` (type=constraint) | `match_conditions`             |
| **Model Selection** | `processor`                              | `generator`                    |
| **Max Results**     | `result_limit` (default: 200)            | `match_limit` (range: 5-1,000) |

### Response Structure

V0 included results in poll responses. V1 separates status and results:

| **Concept**       | **V0 API**                                             | **V1 API**                             |
| ----------------- | ------------------------------------------------------ | -------------------------------------- |
| **Status Check**  | `is_active` + `are_enrichments_active`                 | `status.is_active`                     |
| **Get Results**   | `GET /v1beta/findall/runs/{id}` (included in response) | `GET /v1beta/findall/runs/{id}/result` |
| **Results Array** | `results`                                              | `candidates`                           |
| **Match Data**    | `filter_results` (array)                               | `output` (object)                      |
| **Field Access**  | Loop through array to find key                         | Direct: `output[field_name]["value"]`  |

### Enrichment Handling

V0 included enrichments in initial spec. V1 adds them via separate endpoint:

| **Aspect**            | **V0 API**                                | **V1 API**                                                  |
| --------------------- | ----------------------------------------- | ----------------------------------------------------------- |
| **Definition**        | Part of `columns` array (type=enrichment) | Separate `POST /v1beta/findall/runs/{id}/enrich` call       |
| **Timing**            | At run creation only                      | Anytime after run creation (multiple enrichments supported) |
| **Output Format**     | Separate `enrichment_results` array       | Merged into `output` object with type=enrichment            |
| **Processor Options** | Limited to FindAll processors             | All Task API processors available                           |

## End-to-End Migration Example

This example shows the complete workflow migration, including enrichments:

<CodeGroup>
  ```python V0 API [expandable] theme={"system"}
  import requests
  import time

  API_KEY = "your_api_key"
  BASE_URL = "https://api.parallel.ai"

  # Step 1: Ingest query
  ingest_response = requests.post(
      f"{BASE_URL}/v1beta/findall/ingest",
      headers={"x-api-key": API_KEY},
      json={"query": "Find AI companies that raised Series A in 2024 and get CEO names"}
  )
  findall_spec = ingest_response.json()

  # Step 2: Create run (constraints + enrichments together)
  run_response = requests.post(
      f"{BASE_URL}/v1beta/findall/runs",
      headers={"x-api-key": API_KEY},
      json={
          "findall_spec": findall_spec,
          "processor": "core",
          "result_limit": 100
      }
  )
  findall_id = run_response.json()["findall_id"]

  # Step 3: Poll until both flags are false
  while True:
      poll_response = requests.get(
          f"{BASE_URL}/v1beta/findall/runs/{findall_id}",
          headers={"x-api-key": API_KEY}
      )
      result = poll_response.json()
      if not result["is_active"] and not result["are_enrichments_active"]:
          break
      time.sleep(15)

  # Step 4: Access results from poll response
  for entity in result["results"]:
      print(f"{entity['name']}: Score {entity['score']}")

      # Loop through arrays to find values
      for filter_result in entity["filter_results"]:
          print(f"  {filter_result['key']}: {filter_result['value']}")
      for enrichment in entity["enrichment_results"]:
          print(f"  {enrichment['key']}: {enrichment['value']}")
  ```

  ```python V1 API [expandable] theme={"system"}
  import requests
  import time

  API_KEY = "your_api_key"
  BASE_URL = "https://api.parallel.ai"
  headers = {
      "x-api-key": API_KEY
  }

  # Step 1: Ingest objective
  ingest_response = requests.post(
      f"{BASE_URL}/v1beta/findall/ingest",
      headers=headers,
      json={"objective": "Find AI companies that raised Series A in 2024 and get CEO names"}
  )
  ingest_data = ingest_response.json()

  # Step 2: Create run (constraints only, flattened)
  run_response = requests.post(
      f"{BASE_URL}/v1beta/findall/runs",
      headers=headers,
      json={
          "objective": ingest_data["objective"],
          "entity_type": ingest_data["entity_type"],
          "match_conditions": ingest_data["match_conditions"],
          "generator": "core",
          "match_limit": 50
      }
  )
  findall_id = run_response.json()["findall_id"]

  # Step 3: Add each suggested enrichment through the separate endpoint
  for enrichment in ingest_data.get("enrichments") or []:
      enrichment_payload = {
          "processor": enrichment.get("processor", "core"),
          "output_schema": enrichment["output_schema"],
      }

      enrich_response = requests.post(
          f"{BASE_URL}/v1beta/findall/runs/{findall_id}/enrich",
          headers=headers,
          json=enrichment_payload
      )
      enrich_response.raise_for_status()

  # Step 4: Poll until completed
  while True:
      status_response = requests.get(
          f"{BASE_URL}/v1beta/findall/runs/{findall_id}",
          headers=headers
      )
      run_status = status_response.json()["status"]
      if not run_status["is_active"]:
          if run_status["status"] != "completed":
              raise RuntimeError(f"FindAll run stopped with status: {run_status['status']}")
          break
      time.sleep(10)

  # Step 5: Fetch results from separate endpoint
  result_response = requests.get(
      f"{BASE_URL}/v1beta/findall/runs/{findall_id}/result",
      headers=headers
  )
  result = result_response.json()

  # Step 6: Access results with direct object access
  for candidate in result["candidates"]:
      if candidate["match_status"] == "matched":
          print(candidate["name"])

          # Direct access to all fields (constraints + enrichments merged)
          for field_name, field_data in candidate["output"].items():
              print(f"  {field_name}: {field_data['value']}")
  ```
</CodeGroup>

## Migration Checklist

Complete these steps to migrate from V0 to V1:

### Core Changes

* Change ingest parameter: `query` → `objective`
* Flatten run request: extract `objective`, `entity_type`, `match_conditions` from `findall_spec`
* Rename: `result_limit` → `match_limit`, `processor` → `generator`
* Update status check: poll while `status.is_active`, then inspect the terminal `status.status`
* Fetch results from separate `/result` endpoint
* Update result parsing: `results` → `candidates`
* Change field access: direct object access (`output[field]`) vs array iteration

### Enrichment Changes (if applicable)

* Move enrichments to separate `POST /enrich` call after run creation
* Convert enrichment columns to `output_schema` format (see [Task API](/task-api/guides/specify-a-task#output-schema))
* Update result access: enrichments now merged into `output` object

### Optional Enhancements

* Implement streaming via `/events` endpoint for real-time updates
* Add `exclude_list` to filter out specific candidates
* Use `generator: "preview"` for testing queries before full runs
* Implement `/extend` endpoint to increase match limits dynamically
* Implement `/cancel` endpoint to stop runs early

### Testing

* Validate queries in development environment
* Review pricing impact with generator-based model
* Update error handling for new response schemas
* Monitor performance metrics

## Related Topics

### Core Concepts

* **[Quickstart](/findall-api/findall-quickstart)**: Get started with V1 FindAll API
* **[Candidates](/findall-api/core-concepts/findall-candidates)**: Understand candidate object structure and states
* **[Generators and Pricing](/findall-api/core-concepts/findall-generator-pricing)**: Understand generator options and pricing
* **[Run Lifecycle](/findall-api/core-concepts/findall-lifecycle)**: Understand run statuses and termination

### Features

* **[Preview](/findall-api/features/findall-preview)**: Test queries with 5–10 evaluated candidates before running full searches
* **[Enrichments](/findall-api/features/findall-enrich)**: Extract additional structured data for matched candidates
* **[Extend Runs](/findall-api/features/findall-extend)**: Increase match limits without paying new fixed costs
* **[Cancel Runs](/findall-api/features/findall-cancel)**: Stop runs early to save costs
* **[Streaming Events](/findall-api/features/findall-sse)**: Receive real-time updates via Server-Sent Events
* **[Webhooks](/findall-api/features/findall-webhook)**: Configure HTTP callbacks for run completion and matches
