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

# Leads Management

> Upload, manage, and track leads in your campaigns.

Leads are the recipients of your cold email campaigns. ColdSend supports uploading leads via CSV, adding them individually, and tracking their engagement.

## Lead Status

| Status         | Description                                   |
| -------------- | --------------------------------------------- |
| `PENDING`      | Lead not yet contacted — eligible for sending |
| `QUEUED`       | Email task created, waiting to be sent        |
| `SENT`         | Initial email successfully sent               |
| `OPENED`       | Email was opened (tracking enabled)           |
| `REPLIED`      | Lead replied to email                         |
| `FAILED`       | Email send failed                             |
| `BOUNCED`      | Email bounced after sending                   |
| `UNSUBSCRIBED` | Lead unsubscribed                             |
| `EXTERNAL`     | External/unsolicited incoming lead            |

## Lead Upload via CSV

**POST** `/api/public/v1/campaigns/{campaign_id}/leads`

Upload leads asynchronously via CSV file. The file must include an email column.

```python theme={null}
import requests
import json

campaign_id = "550e8400-e29b-41d4-a716-446655440000"

mapping = {
    "email": "Email",
    "first_name": "First Name",
    "last_name": "Last Name",
    "company": "Company"
}

with open("leads.csv", "rb") as f:
    response = requests.post(
        f"https://api.coldsend.pro/api/public/v1/campaigns/{campaign_id}/leads",
        headers={"X-API-Key": api_key},
        files={"file": f},
        data={"mapping": json.dumps(mapping)}
    )

print(response.json())
```

### CSV Requirements

* Must include an **email** column (required)
* Additional supported columns: `first_name`, `last_name`, `company`
* Custom columns are mapped automatically and available as `{{custom_column_name}}` in your email templates
* Max CSV size: 50MB
* Max leads per upload: 10,000

### Upload Progress

The upload runs asynchronously. Check progress with:

```python theme={null}
response = requests.get(
    f"https://api.coldsend.pro/api/public/v1/campaigns/{campaign_id}/leads/upload/{job_id}",
    headers={"X-API-Key": api_key}
)
```

## Manual Lead Addition

**POST** `/api/public/v1/campaigns/{campaign_id}/leads/manual`

Add a single lead:

```python theme={null}
response = requests.post(
    f"{base_url}/api/public/v1/campaigns/{campaign_id}/leads/manual",
    headers={"X-API-Key": api_key},
    json={
        "email": "john.doe@example.com",
        "first_name": "John",
        "last_name": "Doe",
        "company": "Acme Inc"
    }
)
```

## Listing Leads

**GET** `/api/public/v1/campaigns/{campaign_id}/leads`

List leads with pagination and filtering:

```python theme={null}
response = requests.get(
    f"{base_url}/api/public/v1/campaigns/{campaign_id}/leads?status=PENDING&page=1&limit=20",
    headers={"X-API-Key": api_key}
)
```

### Query Parameters

| Parameter | Description                                                               |
| --------- | ------------------------------------------------------------------------- |
| `page`    | Page number (1-based, default: 1)                                         |
| `limit`   | Items per page (1-100, default: 20)                                       |
| `status`  | Filter by status: `PENDING`, `SENT`, `OPENED`, `REPLIED`, `BOUNCED`, etc. |
| `search`  | Search by email or name                                                   |

## Deleting Leads

**DELETE** `/api/public/v1/campaigns/{campaign_id}/leads`

Only `PENDING` leads (not yet sent) can be deleted:

```python theme={null}
response = requests.delete(
    f"{base_url}/api/public/v1/campaigns/{campaign_id}/leads",
    headers={"X-API-Key": api_key},
    json={
        "lead_ids": [
            "650e8400-e29b-41d4-a716-446655440000",
            "750e8400-e29b-41d4-a716-446655440001"
        ]
    }
)
```

<Warning>
  Leads that have already received emails cannot be deleted. This ensures compliance and prevents data gaps in campaign analytics.
</Warning>

## Get a Single Lead

**GET** `/api/public/v1/campaigns/{campaign_id}/leads/{lead_id}`

Returns full lead data including email interaction history and any replies received from the lead.

```python theme={null}
lead_id = "650e8400-e29b-41d4-a716-446655440000"

response = requests.get(
    f"{base_url}/api/public/v1/campaigns/{campaign_id}/leads/{lead_id}",
    headers={"X-API-Key": api_key}
)
print(response.json())
```

## Update a Lead

**PUT** `/api/public/v1/campaigns/{campaign_id}/leads/{lead_id}`

Update mutable fields on a lead. Only the fields you provide are changed — `custom_fields` uses **merge patch** semantics: existing keys are preserved, keys you send are added or updated, and keys explicitly set to `null` are removed.

Updatable fields: `first_name`, `last_name`, `company`, `custom_fields`.

```python theme={null}
response = requests.put(
    f"{base_url}/api/public/v1/campaigns/{campaign_id}/leads/{lead_id}",
    headers={"X-API-Key": api_key},
    json={
        "first_name": "Jane",
        "company": "New Corp",
        "custom_fields": {
            "industry": "SaaS",
            "old_field": None  # removes this key
        }
    }
)
```

<Info>
  Requires the `leads:update` scope.
</Info>

## Export Leads as CSV

**GET** `/api/public/v1/campaigns/{campaign_id}/leads/export`

Downloads all leads for a campaign as a CSV file — bypasses pagination limits, so every lead is included in a single download. The exported columns are:

`email`, `first_name`, `last_name`, `company`, `status`, `custom_fields` (JSON-encoded), `created_at`

```python theme={null}
response = requests.get(
    f"{base_url}/api/public/v1/campaigns/{campaign_id}/leads/export",
    headers={"X-API-Key": api_key}
)

with open("leads_export.csv", "wb") as f:
    f.write(response.content)
```

The response `Content-Type` is `text/csv` and the `Content-Disposition` header sets the suggested filename.

<Tip>
  Use this endpoint to sync your ColdSend lead data into external CRMs, data warehouses, or spreadsheets without having to page through the list endpoint.
</Tip>

## Next Steps

<CardGroup cols={2}>
  <Card title="Create Campaign" icon="mail" href="/campaigns/create-campaign">
    Set up your campaign with lead mapping configuration.
  </Card>

  <Card title="Personalization" icon="sparkles" href="/campaigns/personalization">
    Use lead data in personalized email content.
  </Card>
</CardGroup>
