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

# Lead lists enrichment

## POST /api/v1/public/lead-lists/:id/enrichment/

Enrich email addresses or phone numbers for prospects in a lead list. Credits are deducted upfront and enrichment happens asynchronously in the background.

Auth: `X-API-Key`

### Path Parameters

* `id` (integer, required): Lead list ID

### Request Body

```json theme={null}
{
  "enrichment_type": "FIND_EMAIL",
  "prospect_limit": 100,
  "mode": "async",
  "webhook_url": "https://your-domain.com/webhook",
  "filters": {},
  "sort_field": "id",
  "sort_direction": "asc"
}
```

### Parameters

| Parameter         | Type    | Required | Default      | Description                                                                   |
| ----------------- | ------- | -------- | ------------ | ----------------------------------------------------------------------------- |
| `enrichment_type` | string  | No       | `FIND_EMAIL` | Type: `FIND_EMAIL`, `FIND_EMAIL_WATERFALL`, or `FIND_PHONE`                   |
| `prospect_limit`  | integer | No       | `100`        | Maximum number of prospects to enrich                                         |
| `mode`            | string  | No       | `async`      | Either `sync` (return results immediately) or `async` (background processing) |
| `webhook_url`     | string  | No       | `null`       | URL to send results to when enrichment completes (async mode only)            |
| `filters`         | object  | No       | `{}`         | Additional filters to apply                                                   |
| `sort_field`      | string  | No       | `id`         | Field to sort by                                                              |
| `sort_direction`  | string  | No       | `asc`        | Sort direction (`asc` or `desc`)                                              |

### Enrichment Types

| Type                   | Description                  | Cost per Lead | When to Use                             |
| ---------------------- | ---------------------------- | ------------- | --------------------------------------- |
| `FIND_EMAIL`           | Basic email finding          | 3 credits     | Fast, cost-effective email discovery    |
| `FIND_EMAIL_WATERFALL` | Multi-provider email finding | 6 credits     | Higher success rate, more comprehensive |
| `FIND_PHONE`           | Phone number finding         | 30 credits    | Mobile and direct phone numbers         |

### Response (Async Mode)

```json theme={null}
{
  "success": true,
  "mode": "async",
  "enrichment_type": "FIND_EMAIL",
  "enriched_count": 100,
  "credits_deducted": 300,
  "remaining_credits": 700,
  "webhook_url": "https://your-domain.com/webhook",
  "message": "Enrichment started in background. Results will be sent to https://your-domain.com/webhook"
}
```

### Response (Sync Mode)

```json theme={null}
{
  "success": true,
  "mode": "sync",
  "enrichment_type": "FIND_EMAIL",
  "total_count": 100,
  "success_count": 87,
  "credits_deducted": 300,
  "remaining_credits": 700,
  "results": [
    {
      "id": 12345,
      "first_name": "John",
      "last_name": "Doe",
      "success": true,
      "data": {
        "email": "john.doe@company.com"
      }
    },
    {
      "id": 12346,
      "first_name": "Jane",
      "last_name": "Smith",
      "success": false,
      "data": {
        "email": null
      },
      "message": "Email not found"
    }
  ]
}
```

### Response Fields

| Field                            | Type    | Description                                           |
| -------------------------------- | ------- | ----------------------------------------------------- |
| `success`                        | boolean | Whether the enrichment was initiated successfully     |
| `mode`                           | string  | `sync` or `async`                                     |
| `enrichment_type`                | string  | The enrichment type used                              |
| `enriched_count` / `total_count` | integer | Number of prospects enriched                          |
| `success_count`                  | integer | (Sync only) Number of successfully enriched prospects |
| `credits_deducted`               | integer | Total credits deducted                                |
| `remaining_credits`              | integer | Your remaining credit balance                         |
| `webhook_url`                    | string  | (Async only) Webhook URL if provided                  |
| `results`                        | array   | (Sync only) Enrichment results for each prospect      |

### How It Works

1. **Validation**: Checks if you have enough credits
2. **Credit Deduction**: Deducts credits upfront from your account
3. **Status Update**: Sets prospects to "Loading..." status
4. **Background Processing**: Enrichment happens asynchronously
5. **Auto-Update**: Prospects are automatically updated when data is found

### Important Notes

* **Asynchronous**: Enrichment happens in the background. Results appear gradually.
* **Credit Deduction**: Credits are deducted immediately, even if enrichment fails for some leads
* **Automatic Filtering**: Only prospects without valid emails/phones are enriched
* **PEOPLE Lists Only**: This endpoint only works for people lists, not company lists
* **Refunds**: If an email/phone is not found, credits may be refunded (varies by type)

### Error Responses

#### 400 Bad Request - Insufficient Credits

```json theme={null}
{
  "success": false,
  "error": "insufficient_credits",
  "message": "Not enough credits. Need 300, have 250"
}
```

#### 400 Bad Request - Wrong List Type

```json theme={null}
{
  "error": "Email/phone enrichment is only available for people lists"
}
```

#### 400 Bad Request - Invalid Enrichment Type

```json theme={null}
{
  "error": "enrichment_type must be FIND_EMAIL, FIND_EMAIL_WATERFALL, or FIND_PHONE"
}
```

#### 404 Not Found

```json theme={null}
{
  "error": "Lead list not found"
}
```

### Example Usage

#### Async Mode (Default)

```bash theme={null}
# Enrich emails asynchronously (background processing)
curl -X POST "https://api.seleqt.ai/api/v1/public/lead-lists/123/enrichment/" \
  -H "X-API-Key: <your-api-key>" \
  -H "Content-Type: application/json" \
  -d '{
    "enrichment_type": "FIND_EMAIL",
    "prospect_limit": 100,
    "mode": "async"
  }'

# With webhook notification
curl -X POST "https://api.seleqt.ai/api/v1/public/lead-lists/123/enrichment/" \
  -H "X-API-Key: <your-api-key>" \
  -H "Content-Type: application/json" \
  -d '{
    "enrichment_type": "FIND_EMAIL",
    "prospect_limit": 100,
    "mode": "async",
    "webhook_url": "https://your-domain.com/webhook/enrichment"
  }'
```

#### Sync Mode (Immediate Results)

```bash theme={null}
# Enrich and get results immediately
curl -X POST "https://api.seleqt.ai/api/v1/public/lead-lists/123/enrichment/" \
  -H "X-API-Key: <your-api-key>" \
  -H "Content-Type: application/json" \
  -d '{
    "enrichment_type": "FIND_EMAIL",
    "prospect_limit": 50,
    "mode": "sync"
  }'
```

#### Python Example: Async Mode with Webhook

```python theme={null}
import requests

API_KEY = "<your-api-key>"
BASE_URL = "https://api.seleqt.ai/api/v1"
LEAD_LIST_ID = 123
WEBHOOK_URL = "https://your-domain.com/webhook/enrichment"

# Step 1: Check cost first
count_response = requests.get(
    f"{BASE_URL}/public/lead-lists/{LEAD_LIST_ID}/enrichment/count/",
    headers={"X-API-Key": API_KEY},
    params={"enrichment_type": "FIND_EMAIL"}
)

count_data = count_response.json()
print(f"Will enrich {count_data['unenriched_count']} prospects")
print(f"Cost: {count_data['total_cost']} credits")

if not count_data['has_enough_credits']:
    print("❌ Not enough credits!")
    exit()

# Step 2: Start async enrichment with webhook
enrich_response = requests.post(
    f"{BASE_URL}/public/lead-lists/{LEAD_LIST_ID}/enrichment/",
    headers={"X-API-Key": API_KEY},
    json={
        "enrichment_type": "FIND_EMAIL",
        "prospect_limit": count_data['unenriched_count'],
        "mode": "async",
        "webhook_url": WEBHOOK_URL
    }
)

enrich_data = enrich_response.json()
if enrich_data['success']:
    print(f"✓ Enrichment started for {enrich_data['enriched_count']} prospects")
    print(f"✓ Results will be sent to {WEBHOOK_URL}")
    print(f"Credits deducted: {enrich_data['credits_deducted']}")
else:
    print(f"❌ Error: {enrich_data.get('message')}")

# Your webhook handler will receive results when complete
# See lead-lists-enrichment-webhook for webhook implementation
```

#### Python Example: Sync Mode (Immediate Results)

```python theme={null}
import requests

API_KEY = "<your-api-key>"
BASE_URL = "https://api.seleqt.ai/api/v1"
LEAD_LIST_ID = 123

# Check cost
count_response = requests.get(
    f"{BASE_URL}/public/lead-lists/{LEAD_LIST_ID}/enrichment/count/",
    headers={"X-API-Key": API_KEY},
    params={"enrichment_type": "FIND_EMAIL"}
)

count_data = count_response.json()

if not count_data['has_enough_credits']:
    print("❌ Not enough credits!")
    exit()

# Enrich in sync mode - returns results immediately
enrich_response = requests.post(
    f"{BASE_URL}/public/lead-lists/{LEAD_LIST_ID}/enrichment/",
    headers={"X-API-Key": API_KEY},
    json={
        "enrichment_type": "FIND_EMAIL",
        "prospect_limit": min(count_data['unenriched_count'], 50),  # Limit for sync
        "mode": "sync"
    }
)

result = enrich_response.json()

if result['success']:
    print(f"✓ Enriched {result['total_count']} prospects")
    print(f"✓ Success: {result['success_count']}/{result['total_count']}")
    print(f"✓ Credits used: {result['credits_deducted']}")

    # Process results immediately
    for prospect in result['results']:
        if prospect['success']:
            email = prospect['data'].get('email')
            print(f"  ✓ {prospect['first_name']} {prospect['last_name']}: {email}")
        else:
            print(f"  ✗ {prospect['first_name']} {prospect['last_name']}: {prospect.get('message')}")
else:
    print(f"❌ Error: {result.get('message')}")
```

### Complete Workflow Example

```python theme={null}
def enrich_lead_list_emails(lead_list_id, max_prospects=100):
    """
    Complete workflow: check cost, enrich, and verify results.
    """
    # 1. Check how many prospects need enrichment
    count_response = requests.get(
        f"{BASE_URL}/public/lead-lists/{lead_list_id}/enrichment/count/",
        headers={"X-API-Key": API_KEY},
        params={"enrichment_type": "FIND_EMAIL"}
    )

    if not count_response.ok:
        print(f"Error checking count: {count_response.text}")
        return

    count_data = count_response.json()
    unenriched = count_data['unenriched_count']

    if unenriched == 0:
        print("✓ All prospects already have emails!")
        return

    print(f"Found {unenriched} prospects without emails")

    # 2. Check if we have enough credits
    if not count_data['has_enough_credits']:
        print(f"❌ Need {count_data['total_cost']} credits, have {count_data['available_credits']}")
        return

    # 3. Limit to max_prospects if needed
    to_enrich = min(unenriched, max_prospects)

    # 4. Start enrichment
    enrich_response = requests.post(
        f"{BASE_URL}/public/lead-lists/{lead_list_id}/enrichment/",
        headers={"X-API-Key": API_KEY},
        json={
            "enrichment_type": "FIND_EMAIL",
            "prospect_limit": to_enrich
        }
    )

    if not enrich_response.ok:
        print(f"Error enriching: {enrich_response.text}")
        return

    enrich_data = enrich_response.json()
    print(f"✓ Enriching {enrich_data['enriched_count']} prospects")
    print(f"✓ {enrich_data['credits_deducted']} credits deducted")
    print(f"✓ {enrich_data['remaining_credits']} credits remaining")

    # 5. Wait a bit and check results
    print("\nWaiting for enrichment to complete...")
    time.sleep(30)  # Wait 30 seconds

    # 6. Get updated leads
    leads_response = requests.get(
        f"{BASE_URL}/public/lead-lists/{lead_list_id}/leads/",
        headers={"X-API-Key": API_KEY},
        params={"page": 1, "page_size": to_enrich}
    )

    leads = leads_response.json()['prospects']
    enriched_count = sum(1 for lead in leads if lead.get('email') and '@' in lead['email'])

    print(f"\n📊 Results:")
    print(f"   {enriched_count}/{to_enrich} prospects now have emails")
    print(f"   Success rate: {(enriched_count/to_enrich)*100:.1f}%")

# Use the function
enrich_lead_list_emails(123, max_prospects=100)
```

### Monitoring Enrichment Progress

Since enrichment happens asynchronously, you can poll the lead list to check progress:

```python theme={null}
def wait_for_enrichment(lead_list_id, timeout=300):
    """
    Poll the lead list until enrichment is complete or timeout.
    """
    start_time = time.time()

    while time.time() - start_time < timeout:
        response = requests.get(
            f"{BASE_URL}/public/lead-lists/{lead_list_id}/leads/",
            headers={"X-API-Key": API_KEY},
            params={"page": 1, "page_size": 100}
        )

        prospects = response.json()['prospects']
        loading_count = sum(1 for p in prospects if p.get('email') == 'Loading...')

        if loading_count == 0:
            print("✓ Enrichment complete!")
            return True

        print(f"Still processing... ({loading_count} prospects remaining)")
        time.sleep(10)

    print("⚠ Timeout reached")
    return False
```

### Best Practices

1. **Check Cost First**: Always use the count endpoint before enriching
2. **Start Small**: Test with a small batch before enriching thousands
3. **Monitor Credits**: Keep track of your credit balance
4. **Batch Processing**: Enrich in batches rather than all at once
5. **Waterfall for Higher Success**: Use `FIND_EMAIL_WATERFALL` for better results (costs more)
6. **Phone Last**: Phone enrichment is expensive (30 credits) - use sparingly
7. **Check Results**: Poll the lead list to verify enrichment completed successfully
