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

# Leads: Enrolling and Managing Outbound Campaign Contacts

> Leads are the contacts enrolled in your campaigns. Leadterra's bulk upsert API lets you add, update, and enroll leads in a single call.

Leads are the people your campaigns reach out to. Each lead is a contact record attached to a specific campaign, carrying the fields your sequence templates use for personalization. Leadterra's bulk upsert endpoint is designed for programmatic GTM workflows — you can push hundreds of leads into a campaign in a single API call, and the platform handles both creation and deduplication automatically.

## Lead fields

Every lead has a set of standard fields. The `email` field is the only required value; all other standard fields are optional but strongly recommended because they power your personalization tokens.

| Field       | Required | Description                                                         |
| ----------- | -------- | ------------------------------------------------------------------- |
| `email`     | ✅ Yes    | The lead's email address. Used as the unique identifier for upsert. |
| `firstName` | No       | First name. Resolves `{{firstName}}` tokens in sequence steps.      |
| `company`   | No       | Company name. Resolves `{{company}}` tokens in sequence steps.      |
| `jobTitle`  | No       | Job title. Resolves `{{jobTitle}}` tokens in sequence steps.        |

Beyond these standard fields, you can pass any additional key-value pairs in the lead object. Leadterra stores them as custom variables and makes them available as personalization tokens using the same `{{fieldName}}` syntax. For example, if you include a `useCase` field, you can reference it in your email body as `{{useCase}}`.

## Upsert semantics

`POST /v1/campaigns/:id/leads/bulk` uses upsert logic, meaning a single call both creates new leads and updates existing ones. Leadterra matches leads by `email` address within the scope of the campaign. If a lead with that email already exists in the campaign, its fields are updated with the values you provide. If no match is found, a new lead record is created.

```bash theme={null}
curl -X POST https://app.leadterra.co/v1/campaigns/camp_01hx4mrqpbcn7wh2gfk9yz6e3s/leads/bulk \
  -H "Authorization: Bearer sk_live_YOUR_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "leads": [
      {
        "email": "priya.sharma@voltmetrics.io",
        "firstName": "Priya",
        "company": "Voltmetrics",
        "jobTitle": "VP of Sales"
      },
      {
        "email": "dan.foster@loopcraft.com",
        "firstName": "Dan",
        "company": "Loopcraft",
        "jobTitle": "Head of Growth",
        "useCase": "outbound pipeline generation"
      }
    ]
  }'
```

**Sample response**

```json theme={null}
{
  "data": {
    "created": 1,
    "updated": 1,
    "enrolled": 2,
    "errors": []
  }
}
```

The response breaks down exactly how many leads were created versus updated in this call, so your automation can log the delta without re-querying the campaign.

## Enrollment

Bulk upsert does not just load contact data — it also enrolls each lead into the campaign at the same time. The moment the call succeeds, newly created leads are queued to receive step one of your sequence. Updated leads that are already enrolled continue from wherever they are in the sequence; their position is not reset.

If the campaign is in `draft` state when you upsert leads, the leads are added to the campaign but will not receive any messages until you call `POST /v1/campaigns/:id/start`. This lets you front-load your lead list before going live.

<Tip>
  Include every field that your sequence steps reference before you enroll leads. Once a campaign is running, missing personalization fields produce empty token substitutions that are visible to your recipients. Populate `firstName`, `company`, and `jobTitle` at minimum, plus any custom tokens your templates use.
</Tip>
