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

# Batch Enrichment

> Trigger contact enrichment for multiple persons in a single batch request

This endpoint triggers enrichment for phone numbers or email addresses for multiple persons at once. It efficiently handles batch processing by reusing existing enrichments and only creating new ones where needed.

## How It Works

The batch enrichment process is optimized to avoid duplicate work:

1. **Check Existing**: For each person, checks if a reusable enrichment already exists (pending or finished)
2. **Credit Validation**: Verifies the organization has sufficient credits for new enrichments
3. **Create Pending**: Creates pending enrichment records for persons without reusable enrichments
4. **Async Processing**: Enrichments are processed asynchronously after the response is returned

<Note>
  Enrichments are processed asynchronously. The response returns immediately
  with enrichment records in `pending` status. Use the enrichment status
  endpoint to poll for completion.
</Note>

## Request

### Body Parameters

<ParamField body="personIds" type="string[]" required>
  Array of person UUIDs to enrich. Each ID must be a valid UUID v4.
  **Constraints:** - Minimum: 1 person ID - Maximum: 100 person IDs per batch
  **Example:** `["550e8400-e29b-41d4-a716-446655440000",
      "6ba7b810-9dad-11d1-80b4-00c04fd430c8"]`
</ParamField>

<ParamField body="field" type="string" required>
  The type of contact data to enrich. **Allowed values:** - `phones` - Enrich
  phone numbers - `emails` - Enrich email addresses
</ParamField>

## Response

Returns an array of enrichment objects. The array includes both reused existing enrichments and newly created pending enrichments.

<ResponseField name="enrichments" type="Enrichment[]" required>
  Array of enrichment objects for the requested persons.

  <Expandable title="Enrichment Object">
    <ResponseField name="id" type="string" required>
      Unique identifier (UUID) of the enrichment record.
    </ResponseField>

    <ResponseField name="createdAt" type="string" required>
      ISO 8601 timestamp when the enrichment was created.
    </ResponseField>

    <ResponseField name="updatedAt" type="string" required>
      ISO 8601 timestamp when the enrichment was last updated.
    </ResponseField>

    <ResponseField name="entityId" type="string" required>
      The person UUID that this enrichment belongs to.
    </ResponseField>

    <ResponseField name="entityType" type="string" required>
      The type of entity being enriched. Always `person` for this endpoint.
    </ResponseField>

    <ResponseField name="field" type="string" required>
      The field being enriched (`phones` or `emails`).
    </ResponseField>

    <ResponseField name="status" type="string" required>
      Current status of the enrichment.

      **Possible values:**

      * `pending` - Enrichment is in progress
      * `finished` - Enrichment completed successfully
      * `failed` - Enrichment failed with an error
      * `timeout` - Enrichment timed out
      * `cancelled` - Enrichment was cancelled
    </ResponseField>

    <ResponseField name="error" type="string | null" required>
      Error message if the enrichment failed. `null` for successful or pending enrichments.
    </ResponseField>

    <ResponseField name="dataFound" type="boolean | null" required>
      Whether contact data was found during enrichment.

      * `null` - Unknown (pending enrichment)
      * `true` - Data was found
      * `false` - No data found for this contact
    </ResponseField>

    <ResponseField name="createdBy" type="string" required>
      User ID who initiated the enrichment.
    </ResponseField>

    <ResponseField name="orgId" type="string" required>
      Organization ID the enrichment belongs to.
    </ResponseField>

    <ResponseField name="globalEnrichmentId" type="string | null" required>
      Reference to the global enrichment record if data was found. `null` for pending or unsuccessful enrichments.
    </ResponseField>

    <ResponseField name="creditTransactionId" type="string | null" required>
      Reference to the credit transaction for this enrichment. `null` until credits are consumed.
    </ResponseField>

    <ResponseField name="value" type="unknown | null">
      Optional enrichment payload value. Present for enrichments that return data (e.g., company summaries). `null` or omitted for standard phone/email enrichments.
    </ResponseField>
  </Expandable>
</ResponseField>

## Credits

Enrichment operations consume credits from your organization's balance:

* **Email enrichment**: Credits are deducted per successful enrichment
* **Phone enrichment**: Credits are deducted per successful enrichment

<Warning>
  The endpoint validates credit availability before creating enrichments. If
  insufficient credits are available, the request will fail with an
  `INSUFFICIENT_CREDITS` error.
</Warning>

<RequestExample>
  ```bash cURL theme={null}
  curl -X POST "https://app.lance.so/api/v1/operations/enrichment/batch" \
    -H "Authorization: Bearer <token>" \
    -H "Content-Type: application/json" \
    -d '{
      "personIds": [
        "550e8400-e29b-41d4-a716-446655440000",
        "6ba7b810-9dad-11d1-80b4-00c04fd430c8"
      ],
      "field": "emails"
    }'
  ```

  ```javascript JavaScript theme={null}
  const response = await fetch("/api/v1/operations/enrichment/batch", {
    method: "POST",
    headers: {
      Authorization: "Bearer <token>",
      "Content-Type": "application/json",
    },
    body: JSON.stringify({
      personIds: [
        "550e8400-e29b-41d4-a716-446655440000",
        "6ba7b810-9dad-11d1-80b4-00c04fd430c8",
      ],
      field: "emails",
    }),
  });

  const enrichments = await response.json();
  ```

  ```typescript TypeScript theme={null}
  interface Enrichment {
    id: string;
    createdAt: string;
    updatedAt: string;
    entityId: string;
    entityType: "person" | "company" | "leadlist";
    field: "phones" | "emails";
    status: "pending" | "finished" | "failed" | "timeout" | "cancelled";
    error: string | null;
    dataFound: boolean | null;
    createdBy: string;
    orgId: string;
    globalEnrichmentId: string | null;
    creditTransactionId: string | null;
  }

  const response = await fetch("/api/v1/operations/enrichment/batch", {
    method: "POST",
    headers: {
      Authorization: "Bearer <token>",
      "Content-Type": "application/json",
    },
    body: JSON.stringify({
      personIds: [
        "550e8400-e29b-41d4-a716-446655440000",
        "6ba7b810-9dad-11d1-80b4-00c04fd430c8",
      ],
      field: "emails",
    }),
  });

  const enrichments: Enrichment[] = await response.json();
  ```
</RequestExample>

<ResponseExample>
  ```json Success Response theme={null}
  [
    {
      "id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
      "createdAt": "2024-01-15T10:30:00.000Z",
      "updatedAt": "2024-01-15T10:30:00.000Z",
      "entityId": "550e8400-e29b-41d4-a716-446655440000",
      "entityType": "person",
      "field": "emails",
      "status": "pending",
      "error": null,
      "dataFound": null,
      "createdBy": "user_abc123",
      "orgId": "org_xyz789",
      "globalEnrichmentId": null,
      "creditTransactionId": null
    },
    {
      "id": "b2c3d4e5-f6a7-8901-bcde-f12345678901",
      "createdAt": "2024-01-14T08:00:00.000Z",
      "updatedAt": "2024-01-14T08:05:00.000Z",
      "entityId": "6ba7b810-9dad-11d1-80b4-00c04fd430c8",
      "entityType": "person",
      "field": "emails",
      "status": "finished",
      "error": null,
      "dataFound": true,
      "createdBy": "user_abc123",
      "orgId": "org_xyz789",
      "globalEnrichmentId": "c3d4e5f6-a7b8-9012-cdef-123456789012",
      "creditTransactionId": "d4e5f6a7-b8c9-0123-def1-234567890123"
    }
  ]
  ```

  ```json Error Response (Validation Error) theme={null}
  {
    "error": {
      "code": "VALIDATION_ERROR",
      "message": "At least one person ID is required"
    }
  }
  ```

  ```json Error Response (Batch Size Exceeded) theme={null}
  {
    "error": {
      "code": "VALIDATION_ERROR",
      "message": "Maximum 100 person IDs allowed per batch"
    }
  }
  ```

  ```json Error Response (Invalid Field) theme={null}
  {
    "error": {
      "code": "VALIDATION_ERROR",
      "message": "Invalid input"
    }
  }
  ```

  ```json Error Response (Insufficient Credits) theme={null}
  {
    "error": {
      "code": "INSUFFICIENT_CREDITS",
      "message": "Insufficient credits for 5 enrichments. Required: 50 credits.",
      "details": {
        "operationType": "enrichment_email",
        "count": 5,
        "required": 50
      }
    }
  }
  ```

  ```json Error Response (Unauthorized) theme={null}
  {
    "error": {
      "code": "VALIDATION_ERROR",
      "message": "User ID is missing"
    }
  }
  ```
</ResponseExample>

## Error Codes

| Status Code | Error Code             | Description                                                             |
| ----------- | ---------------------- | ----------------------------------------------------------------------- |
| `400`       | `VALIDATION_ERROR`     | Invalid request body, missing required fields, or constraint violations |
| `401`       | `VALIDATION_ERROR`     | Missing user ID or organization ID (authentication required)            |
| `402`       | `INSUFFICIENT_CREDITS` | Organization does not have enough credits for the requested enrichments |
| `500`       | `INTERNAL_ERROR`       | Server error during enrichment processing                               |

## Notes

* **Reusable Enrichments**: If a person already has a pending or finished enrichment for the requested field, the existing enrichment is returned instead of creating a new one
* **Failed Enrichments**: If a previous enrichment for a person failed, timed out, or was cancelled, a new enrichment will be created
* **Async Processing**: The actual enrichment work happens asynchronously after the API response. Poll the enrichment status endpoint to check for completion
* **Batch Efficiency**: Use this endpoint instead of individual enrichment requests when enriching multiple persons to reduce API calls and improve throughput
