> ## 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 workflow

## Lead Lists Workflow Guide

This guide demonstrates how to use the Lead Lists API endpoints together to build a complete workflow for managing leads.

### Overview

The Lead Lists API provides a complete set of endpoints for:

1. **Searching** for prospects or companies using filters
2. **Creating** lead lists (people or company lists)
3. **Adding** found leads to your lists
4. **Retrieving** leads from your lists
5. **Deleting** leads from your lists
6. **Importing** leads into campaigns

### Complete Workflow Example

#### Step 1: Create a Lead List

First, create a new lead list. Choose the type based on whether you want to manage people or companies.

```python theme={null}
import requests

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

# Create a people list
response = requests.post(
    f"{BASE_URL}/public/lead-lists/",
    headers={"X-API-Key": API_KEY},
    json={
        "name": "Tech CEOs for Q4 Campaign",
        "search_type": "PEOPLE"
    }
)

lead_list = response.json()["lead_list"]
lead_list_id = lead_list["id"]
print(f"Created lead list: {lead_list['name']} (ID: {lead_list_id})")
```

#### Step 2: Search for Prospects

Search for prospects using various filters. The search respects your organization's search limits.

```python theme={null}
# Search for prospects with specific criteria
search_response = requests.post(
    f"{BASE_URL}/public/prospects/search/",
    headers={"X-API-Key": API_KEY},
    json={
        "search_type": "PEOPLE",
        "page": 1,
        "page_size": 100,
        "filters": {
            "job_title": "CEO",
            "location": "United States",
            "industry": "Technology",
            "company_size": "51-200"
        }
    }
)

search_data = search_response.json()
print(f"Found {search_data['total_count']} prospects")
prospects = search_data["prospects"]
```

#### Step 3: Add Prospects to Your List

Extract the prospect IDs from search results and add them to your lead list.

```python theme={null}
# Get prospect IDs
prospect_ids = [p["id"] for p in prospects[:50]]  # Add first 50

# Add to lead list
add_response = requests.post(
    f"{BASE_URL}/public/lead-lists/{lead_list_id}/add-leads/",
    headers={"X-API-Key": API_KEY},
    json={"prospect_ids": prospect_ids}
)

print(f"Added {add_response.json()['added_count']} prospects to list")
```

#### Step 4: Review and Filter Your List

Retrieve leads from your list with additional filtering or sorting.

```python theme={null}
# Get all leads from the list
list_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,
        "sort_field": "last_name",
        "sort_direction": "asc"
    }
)

list_data = list_response.json()
print(f"List contains {list_data['total_count']} total prospects")
```

#### Step 5: Clean Up Your List (Optional)

Remove prospects that don't meet your criteria.

```python theme={null}
# Find prospects to remove (e.g., based on some criteria)
prospects_to_remove = [p["id"] for p in list_data["prospects"] if some_condition(p)]

if prospects_to_remove:
    delete_response = requests.delete(
        f"{BASE_URL}/public/lead-lists/{lead_list_id}/delete-leads/",
        headers={"X-API-Key": API_KEY},
        json={"prospect_ids": prospects_to_remove}
    )
    print(f"Removed {delete_response.json()['deleted_count']} prospects")
```

#### Step 6: Enrich Email/Phone (Optional)

Before importing to campaigns, you may want to enrich missing contact information.

```python theme={null}
# Check how many prospects need email enrichment
enrich_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"}
)

enrich_count = enrich_count_response.json()
print(f"Prospects without emails: {enrich_count['unenriched_count']}")
print(f"Cost to enrich: {enrich_count['total_cost']} credits")

# Enrich emails if you have enough credits
if enrich_count['has_enough_credits'] and enrich_count['unenriched_count'] > 0:
    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": enrich_count['unenriched_count']
        }
    )

    if enrich_response.json()['success']:
        print(f"Enriching emails for {enrich_count['unenriched_count']} prospects...")
        # Enrichment happens in background
        time.sleep(30)  # Wait for some results
```

#### Step 7: Import to Campaign

Once your list is ready, import it into a campaign for outreach.

```python theme={null}
# Get or create a campaign
campaign_response = requests.post(
    f"{BASE_URL}/public/campaigns/",
    headers={"X-API-Key": API_KEY},
    json={
        "name": "Q4 Tech CEO Outreach",
        "status": "DRAFT"
    }
)

campaign_id = campaign_response.json()["campaign"]["id"]

# Import leads from list to campaign
import_response = requests.post(
    f"{BASE_URL}/public/campaigns/{campaign_id}/import/",
    headers={"X-API-Key": API_KEY},
    json={
        "source": "lead_list",
        "lead_list_id": lead_list_id,
        "amount": 100  # Number of leads to import
    }
)

print(f"Imported leads into campaign")
```

### Working with Company Lists

The workflow for company lists is similar, but uses `company_ids` instead of `prospect_ids`.

```python theme={null}
# Create a company list
company_list_response = requests.post(
    f"{BASE_URL}/public/lead-lists/",
    headers={"X-API-Key": API_KEY},
    json={
        "name": "SaaS Companies to Target",
        "search_type": "COMPANY"
    }
)

company_list_id = company_list_response.json()["lead_list"]["id"]

# Search for companies
company_search_response = requests.post(
    f"{BASE_URL}/public/prospects/search/",
    headers={"X-API-Key": API_KEY},
    json={
        "search_type": "COMPANY",
        "filters": {
            "industry": "Software",
            "company_size": "11-50",
            "location": "United States"
        }
    }
)

companies = company_search_response.json()["companies"]
company_ids = [c["id"] for c in companies]

# Add companies to list
requests.post(
    f"{BASE_URL}/public/lead-lists/{company_list_id}/add-leads/",
    headers={"X-API-Key": API_KEY},
    json={"company_ids": company_ids}
)
```

### Advanced: Batch Processing

For large-scale operations, use pagination to process all results.

```python theme={null}
def search_all_prospects(filters, search_type="PEOPLE"):
    """Search all prospects matching filters across all pages."""
    all_prospects = []
    page = 1

    while True:
        response = requests.post(
            f"{BASE_URL}/public/prospects/search/",
            headers={"X-API-Key": API_KEY},
            json={
                "search_type": search_type,
                "page": page,
                "page_size": 100,
                "filters": filters
            }
        )

        data = response.json()
        prospects = data["prospects"]
        all_prospects.extend(prospects)

        # Check if we've reached the last page
        if len(prospects) < 100:
            break

        page += 1

    return all_prospects

# Use the function
all_ceos = search_all_prospects({
    "job_title": "CEO",
    "industry": "Technology"
})

print(f"Found {len(all_ceos)} total CEOs")
```

### Error Handling

Always implement proper error handling in production code.

```python theme={null}
def safe_api_call(method, url, **kwargs):
    """Make API call with error handling."""
    try:
        response = method(url, **kwargs)
        response.raise_for_status()
        return response.json()
    except requests.exceptions.HTTPError as e:
        print(f"HTTP Error: {e}")
        print(f"Response: {e.response.text}")
        return None
    except Exception as e:
        print(f"Error: {e}")
        return None

# Use safe API calls
data = safe_api_call(
    requests.post,
    f"{BASE_URL}/public/prospects/search/",
    headers={"X-API-Key": API_KEY},
    json={"search_type": "PEOPLE", "filters": {"job_title": "CEO"}}
)

if data and data.get("success"):
    prospects = data["prospects"]
    # Process prospects
```

### Enrichment Workflow

Email and phone enrichment is a powerful feature for lead lists:

```python theme={null}
def enrich_lead_list(lead_list_id, enrichment_type="FIND_EMAIL"):
    """
    Complete enrichment workflow with error handling.
    """
    # Step 1: 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": enrichment_type}
    )

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

    count_data = count_response.json()

    # Step 2: Validate we have enough credits
    if not count_data['has_enough_credits']:
        print(f"Insufficient credits: need {count_data['total_cost']}, have {count_data['available_credits']}")
        return False

    if count_data['unenriched_count'] == 0:
        print("No prospects need enrichment")
        return True

    # Step 3: Confirm with user (in production, you might skip this)
    print(f"Will enrich {count_data['unenriched_count']} prospects")
    print(f"Cost: {count_data['total_cost']} credits")

    # Step 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": enrichment_type,
            "prospect_limit": count_data['unenriched_count']
        }
    )

    if enrich_response.ok:
        result = enrich_response.json()
        print(f"✓ Enrichment started: {result['enriched_count']} prospects")
        print(f"✓ Credits deducted: {result['credits_deducted']}")
        return True
    else:
        print(f"Error: {enrich_response.text}")
        return False

# Use it
enrich_lead_list(123, "FIND_EMAIL")
```

### Best Practices

1. **Pagination**: Always use pagination when dealing with large result sets
2. **Error Handling**: Implement retry logic for transient errors
3. **Rate Limiting**: Be mindful of API rate limits
4. **Search Limits**: Monitor your organization's monthly search limit
5. **Data Validation**: Validate prospect/company IDs before adding to lists
6. **List Organization**: Use descriptive names for your lead lists
7. **Regular Cleanup**: Remove outdated or invalid leads periodically
8. **Check Enrichment Costs**: Always check costs before enriching
9. **Enrich Strategically**: Email enrichment is cheaper than phone (3 vs 30 credits)
10. **Monitor Credits**: Keep track of your credit balance to avoid interruptions

### API Endpoints Summary

| Endpoint                                   | Method | Purpose                        |
| ------------------------------------------ | ------ | ------------------------------ |
| `/public/lead-lists/`                      | POST   | Create a lead list             |
| `/public/lead-lists/`                      | GET    | List all lead lists            |
| `/public/prospects/search/`                | POST   | Search for prospects/companies |
| `/public/lead-lists/:id/add-leads/`        | POST   | Add leads to a list            |
| `/public/lead-lists/:id/leads/`            | GET    | Get leads from a list          |
| `/public/lead-lists/:id/delete-leads/`     | DELETE | Delete leads from a list       |
| `/public/lead-lists/:id/enrichment/count/` | GET    | Get enrichment cost estimate   |
| `/public/lead-lists/:id/enrichment/`       | POST   | Enrich emails/phones           |
| `/public/lead-lists/:id/import/`           | POST   | Import leads to a list         |
| `/public/campaigns/{id}/import/`           | POST   | Import leads to a campaign     |
