# Add Leads via API

> POST /v1/campaigns/{id}/leads - push leads from your CRM into a running Edesy agent-dialer campaign, with your own external_id and custom fields echoed back on results and webhooks.

Source: https://edesy.in/docs/voice-api/campaigns/add-leads-via-api

`POST https://voice-api.edesy.in/v1/campaigns/{id}/leads`

Push leads from your CRM into an agent-dialer campaign while it runs. Each lead can carry your own record ID (`external_id`) and any `custom_fields`; agents see the fields, and both come back in results and webhook events, so your CRM never needs to store Edesy IDs. Numbers on your DNC list and duplicates are suppressed automatically.

## Request

```bash
curl -X POST https://voice-api.edesy.in/v1/campaigns/{id}/leads \
  -H "Authorization: Bearer $EDESY_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "leads": [
      {
        "phone_number": "+9198XXXXXXXX",
        "name": "Asha Rao",
        "external_id": "crm-lead-77812",
        "consent_source": "website_form",
        "consent_timestamp": "2026-10-27T18:04:00Z",
        "custom_fields": { "city": "Pune", "product": "Home loan", "loan_amount": 2500000 }
      }
    ]
  }'
```

| Field | Type | Required | Description |
|---|---|---|---|
| `leads` | array | yes | One or more leads |
| `leads[].phone_number` | string | yes | Number to call |
| `leads[].name` | string | no | Shown to the agent |
| `leads[].external_id` | string | no | Your CRM's record ID. Returned on results and webhooks |
| `leads[].custom_fields` | object | no | Any attributes. Shown to the agent and returned verbatim |
| `leads[].consent_source`, `leads[].consent_timestamp` | string | no | Where and when consent was given |

## Response

```json
{
  "data": {
    "contacts_added": 1,
    "total_rows": 1,
    "suppressed_dnc": 0,
    "suppressed_duplicate": 0,
    "invalid": 0,
    "invalid_samples": [],
    "consent_timestamp_unparsed": 0
  }
}
```

## Rules

- The campaign must be an agent-dialer campaign (created with `queue_id`). For broadcast campaigns, use `POST /v1/campaigns/{id}/contacts`.
- Leads can be added while the campaign is draft, scheduled, running or paused, but not after it is completed or stopped.
- An empty `leads` array returns `400`.

## Getting results back into your CRM

Create a [webhook subscription](https://edesy.in/docs/voice-api/webhooks/subscriptions) and you receive, for each lead:

| Event | When |
|---|---|
| `call.answered` | The lead picked up |
| `call.completed` | The call ended, with `status`, `duration_sec`, `sip_status` and `answered_by` |
| `recording.ready` | The recording is playable |
| `disposition.submitted` | The agent submitted a wrap-up code, with `disposition` and `agent` |

Each event's `data` carries your `external_id` and `custom_fields`, so you can update the lead directly.

```json
{
  "event": "disposition.submitted",
  "timestamp": "2026-10-28T11:20:31Z",
  "data": {
    "call_sid": "CA_6f1c2d3e-0000-4000-8000-000000000000",
    "external_id": "crm-lead-77812",
    "campaign_id": "...",
    "contact_id": "...",
    "to": "+9198XXXXXXXX",
    "direction": "outbound",
    "agent": { "id": "...", "name": "Priya" },
    "disposition": { "id": "...", "name": "Interested", "is_terminal": true, "notes": "Call back Friday" },
    "custom_fields": { "city": "Pune", "product": "Home loan", "loan_amount": 2500000 }
  }
}
```
