Skip to main content
Leads are the contacts your campaign will reach out to. Leadterra’s bulk upsert endpoint lets you enroll hundreds of leads in a single API call, automatically deduplicating by email address so you never create duplicate records. This guide covers preparing your leads payload, sending the request, and confirming enrollment before you start the campaign.
1

Prepare your leads array

Each lead object requires an email field. All other fields are optional but recommended — they power the {{firstName}}, {{company}}, and {{jobTitle}} personalization tokens in your sequence steps.
FieldRequiredDescription
emailPrimary identifier; used for deduplication
firstNameRecommendedMaps to {{firstName}} token
lastNameOptionalMaps to {{lastName}} token
companyRecommendedMaps to {{company}} token
jobTitleOptionalMaps to {{jobTitle}} token
customFieldsOptionalKey-value object for custom tokens
Here’s an example leads array with three contacts ready for enrollment:
{
  "leads": [
    {
      "email": "ava@acmecorp.com",
      "firstName": "Ava",
      "lastName": "Chen",
      "company": "Acme Corp",
      "jobTitle": "VP Sales"
    },
    {
      "email": "marcus@buildfast.io",
      "firstName": "Marcus",
      "lastName": "Webb",
      "company": "BuildFast",
      "jobTitle": "Head of Growth"
    },
    {
      "email": "priya@nexusai.com",
      "firstName": "Priya",
      "lastName": "Sharma",
      "company": "Nexus AI",
      "jobTitle": "Director of Revenue"
    }
  ]
}
2

Send the bulk upsert

Post your leads array to POST /v1/campaigns/:id/leads/bulk, replacing :id with the campaign ID from your campaign creation step. Leadterra will enroll each lead and resolve any personalization tokens against their fields.
curl -X POST https://app.leadterra.co/v1/campaigns/camp_01HZA1TPNQ8RD4KF/leads/bulk \
  -H "Authorization: Bearer sk_live_YOUR_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "leads": [
      {
        "email": "ava@acmecorp.com",
        "firstName": "Ava",
        "lastName": "Chen",
        "company": "Acme Corp",
        "jobTitle": "VP Sales"
      },
      {
        "email": "marcus@buildfast.io",
        "firstName": "Marcus",
        "lastName": "Webb",
        "company": "BuildFast",
        "jobTitle": "Head of Growth"
      },
      {
        "email": "priya@nexusai.com",
        "firstName": "Priya",
        "lastName": "Sharma",
        "company": "Nexus AI",
        "jobTitle": "Director of Revenue"
      }
    ]
  }'
3

Verify enrollment

A successful response reports how many leads were enrolled and how many were updated rather than newly created.
{
  "result": {
    "enrolled": 3,
    "updated": 0,
    "skipped": 0,
    "totalInCampaign": 3
  }
}
If a lead with the same email address already exists in the campaign, Leadterra updates their record with any new field values instead of creating a duplicate entry. The updated count reflects these upserts, and the lead’s position in the sequence is preserved — they won’t receive any step they’ve already been sent.The skipped count covers addresses that appear on your workspace suppression list and were silently excluded from enrollment.
4

Start the campaign

If the campaign isn’t already running, start it now with POST /v1/campaigns/:id/start. Leadterra will immediately begin queueing the first sequence step for every enrolled lead.
curl -X POST https://app.leadterra.co/v1/campaigns/camp_01HZA1TPNQ8RD4KF/start \
  -H "Authorization: Bearer sk_live_YOUR_KEY"
{
  "campaign": {
    "id": "camp_01HZA1TPNQ8RD4KF",
    "status": "running",
    "startedAt": "2025-06-10T15:00:00Z",
    "leadsEnrolled": 3,
    "queuedMessages": 3
  }
}
You can also add more leads to a campaign that’s already running — they’ll be enrolled and queued immediately.
Every personalization token in your sequence steps — like {{firstName}} or {{company}} — must have a matching field on the lead object. If a field is missing, the token renders as an empty string. Always verify your leads array includes the fields your copy depends on before enrolling.
For very large lists (10,000+ leads), split your array into batches of 500–1,000 leads per request. Smaller batches reduce timeout risk and make it easier to identify and retry any failed rows.