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

# Add Leads

> Add one or more leads to an existing campaign

Add new leads to an existing campaign. The leads will be queued for processing according to the campaign's sequence.

## Request

<ParamField header="X-API-Key" type="string" required>
  Your API key
</ParamField>

<ParamField body="campaignId" type="string" required>
  The campaign ID to add leads to
</ParamField>

<ParamField body="leads" type="array" required>
  Array of lead objects to add (max 100 per request)

  <Expandable title="Lead Object">
    <ParamField body="linkedinUrl" type="string" required>
      LinkedIn profile URL of the lead. This is the only required field.
    </ParamField>

    <ParamField body="firstName" type="string">
      Lead's first name (optional, will be scraped if not provided)
    </ParamField>

    <ParamField body="lastName" type="string">
      Lead's last name (optional, will be scraped if not provided)
    </ParamField>

    <ParamField body="email" type="string">
      Lead's email address
    </ParamField>

    <ParamField body="company" type="string">
      Lead's company name
    </ParamField>

    <ParamField body="title" type="string">
      Lead's job title
    </ParamField>
  </Expandable>

  <Note>
    **Custom fields:** You can pass any additional custom fields as flat properties directly on each lead object. See the [Dynamic/Custom Fields](#dynamiccustom-fields) section below for details.
  </Note>
</ParamField>

## Dynamic/Custom Fields

Leads support **dynamic custom fields** that can be passed as flat properties alongside the required `linkedinUrl`. This allows you to include any additional data for personalization in your campaign messages.

<Info>
  **How it works:** Simply add any custom key-value pairs directly to the lead object. There's no need for a nested `customFields` object—all properties are accepted at the top level.
</Info>

**Common use cases for custom fields:**

* `industry` - Lead's industry for targeted messaging
* `region` - Geographic region for localized outreach
* `referredBy` - Referral source tracking
* `customScore` - Lead scoring from your CRM
* `eventName` - Conference or event where you met
* `icebreaker` - Pre-written personalized opener

## Response

<ResponseField name="success" type="boolean">
  Whether the operation completed successfully
</ResponseField>

<ResponseField name="leadsAdded" type="integer">
  Number of leads successfully added
</ResponseField>

<ResponseField name="duplicatesSkipped" type="integer">
  Number of leads skipped (already exist in campaign)
</ResponseField>

<ResponseField name="invalidEntries" type="integer">
  Number of leads with invalid data
</ResponseField>

<ResponseField name="errors" type="array">
  Array of error objects for leads that failed validation (only present if there are errors)

  <Expandable title="Error Object">
    <ResponseField name="index" type="integer">
      Index of the failed lead in the input array
    </ResponseField>

    <ResponseField name="linkedinUrl" type="string">
      The LinkedIn URL that failed
    </ResponseField>

    <ResponseField name="reason" type="string">
      Reason for the failure
    </ResponseField>
  </Expandable>
</ResponseField>

<RequestExample>
  ```bash cURL theme={null}
  curl -X POST https://api.sendpilot.ai/v1/leads \
    -H "X-API-Key: YOUR_API_KEY" \
    -H "Content-Type: application/json" \
    -d '{
      "campaignId": "camp_xyz789",
      "leads": [
        {
          "linkedinUrl": "https://www.linkedin.com/in/john-doe",
          "firstName": "John",
          "lastName": "Doe",
          "company": "TechCorp",
          "title": "VP of Engineering",
          "industry": "Technology",
          "region": "North America"
        },
        {
          "linkedinUrl": "https://www.linkedin.com/in/jane-smith",
          "firstName": "Jane",
          "lastName": "Smith",
          "referredBy": "Conference 2024",
          "customScore": 85,
          "icebreaker": "Loved your talk on AI automation"
        }
      ]
    }'
  ```

  ```javascript Node.js theme={null}
  const response = await fetch('https://api.sendpilot.ai/v1/leads', {
    method: 'POST',
    headers: {
      'X-API-Key': process.env.SENDPILOT_API_KEY,
      'Content-Type': 'application/json'
    },
    body: JSON.stringify({
      campaignId: 'camp_xyz789',
      leads: [
        {
          linkedinUrl: 'https://www.linkedin.com/in/john-doe',
          firstName: 'John',
          lastName: 'Doe',
          company: 'TechCorp',
          // Custom fields passed directly
          industry: 'SaaS',
          leadSource: 'Website Demo Request'
        }
      ]
    })
  });
  const result = await response.json();
  ```

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

  response = requests.post(
      'https://api.sendpilot.ai/v1/leads',
      headers={
          'X-API-Key': 'YOUR_API_KEY',
          'Content-Type': 'application/json'
      },
      json={
          'campaignId': 'camp_xyz789',
          'leads': [
              {
                  'linkedinUrl': 'https://www.linkedin.com/in/john-doe',
                  'firstName': 'John',
                  'lastName': 'Doe',
                  # Custom fields as flat properties
                  'eventName': 'SaaStr 2024',
                  'boothVisit': True,
                  'interestLevel': 'High'
              }
          ]
      }
  )
  result = response.json()
  ```
</RequestExample>

<ResponseExample>
  ```json 201 theme={null}
  {
    "success": true,
    "leadsAdded": 2,
    "duplicatesSkipped": 0,
    "invalidEntries": 0
  }
  ```

  ```json 207 Multi-Status theme={null}
  {
    "success": true,
    "leadsAdded": 1,
    "duplicatesSkipped": 1,
    "invalidEntries": 1,
    "errors": [
      {
        "index": 2,
        "linkedinUrl": "invalid-url",
        "reason": "Invalid LinkedIn URL format"
      }
    ]
  }
  ```

  ```json 404 theme={null}
  {
    "statusCode": 404,
    "error": "Not Found",
    "code": "CAMPAIGN_NOT_FOUND",
    "message": "Campaign with ID 'camp_xyz789' not found in this workspace"
  }
  ```
</ResponseExample>

<Note>
  Duplicate detection is based on the LinkedIn URL. If a lead with the same URL already exists in the campaign, it will be skipped.
</Note>

<Tip>
  **Using custom fields in messages:** Reference your custom fields in campaign message templates using the `{{fieldName}}` syntax. For example, if you pass `industry: "Technology"`, use `{{industry}}` in your message template.
</Tip>


## OpenAPI

````yaml POST /v1/leads
openapi: 3.0.0
info:
  title: SendPilot External API
  description: >
    The SendPilot API enables you to programmatically manage LinkedIn outreach
    campaigns,

    add leads, update lead statuses, send messages, and receive real-time
    webhook notifications.
  version: 1.0.0
  contact:
    name: SendPilot Support
    email: support@sendpilot.ai
    url: https://sendpilot.ai
servers:
  - url: https://api.sendpilot.ai
    description: Production server
security:
  - ApiKeyAuth: []
tags:
  - name: Credits
    description: Credits and quota management
  - name: Campaigns
    description: Campaign management endpoints
  - name: Leads
    description: Lead management endpoints
  - name: Lead Database
    description: Lead Database search endpoints
  - name: Lead Extractor
    description: Lead extraction campaign endpoints
  - name: Inbox
    description: Direct messaging endpoints
paths:
  /v1/leads:
    post:
      tags:
        - Leads
      summary: Add leads to campaign
      description: Add one or more leads to an existing campaign
      operationId: addLeadsToCampaign
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/AddLeadsRequest'
      responses:
        '201':
          description: Leads added successfully
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/AddLeadsResponse'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '404':
          $ref: '#/components/responses/NotFound'
components:
  schemas:
    AddLeadsRequest:
      type: object
      properties:
        campaignId:
          type: string
          description: Campaign ID to add leads to
        leads:
          type: array
          items:
            $ref: '#/components/schemas/LeadInput'
          minItems: 1
          maxItems: 100
      required:
        - campaignId
        - leads
    AddLeadsResponse:
      type: object
      properties:
        success:
          type: boolean
        leadsAdded:
          type: integer
        duplicatesSkipped:
          type: integer
        invalidEntries:
          type: integer
        errors:
          type: array
          items:
            $ref: '#/components/schemas/AddLeadsError'
      required:
        - success
        - leadsAdded
        - duplicatesSkipped
        - invalidEntries
    LeadInput:
      type: object
      description: >
        Lead object with required LinkedIn URL and optional fields.

        Any additional properties beyond the defined ones will be stored as
        custom fields

        for personalization in campaign messages.
      additionalProperties: true
      properties:
        linkedinUrl:
          type: string
          description: LinkedIn profile URL (required)
          example: https://www.linkedin.com/in/johndoe
        firstName:
          type: string
          description: First name (optional)
        lastName:
          type: string
          description: Last name (optional)
        email:
          type: string
          description: Email address (optional)
        company:
          type: string
          description: Company name (optional)
        title:
          type: string
          description: Job title (optional)
      required:
        - linkedinUrl
      example:
        linkedinUrl: https://www.linkedin.com/in/johndoe
        firstName: John
        lastName: Doe
        company: TechCorp
        title: VP of Engineering
        industry: Technology
        region: North America
    AddLeadsError:
      type: object
      properties:
        index:
          type: integer
        linkedinUrl:
          type: string
        reason:
          type: string
      required:
        - index
        - linkedinUrl
        - reason
    Error:
      type: object
      properties:
        statusCode:
          type: integer
        error:
          type: string
        code:
          type: string
        message:
          type: string
      required:
        - statusCode
        - message
  responses:
    BadRequest:
      description: Bad request
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
    Unauthorized:
      description: Unauthorized
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
    NotFound:
      description: Resource not found
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
  securitySchemes:
    ApiKeyAuth:
      type: apiKey
      in: header
      name: X-API-Key
      description: API key for authentication

````