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

# Import Leads from List to Campaign

> Bulk-import every row of a user-owned list into a campaign as leads, pulling enrichment data from profile_data.

**CLI:**

```bash theme={null}
puffle campaign lead import --id <id> --list-id <list-id>
puffle campaign lead import --id <id> --list-id <list-id> --filter <filter>
```

## Overview

Hydrates canonical Leads from a saved List into the campaign as leads. The server pages through `/api/lists/{id}/leads` style canonical memberships and maps each Lead into the campaign lead shape.

* LinkedIn campaigns use the Lead's LinkedIn social URL.
* Email campaigns use the Lead's work-email contact or email attribute when present.
* Profile fields come from canonical Lead fields and Lead attributes.

Invalid rows (missing the required identity for the campaign channel) are skipped. Duplicates are caught by the DB unique constraint. Campaign stats are recomputed atomically after insert.

## AI agent notes

<Note>
  **Channel-specific validation.** Email campaigns require a usable email on the Lead. LinkedIn campaigns require a real LinkedIn URL on the Lead's socials.

  **Response shapes.**

  * `200` — import succeeded (fully or partially); `imported`, `duplicates`, `invalid`, `errors`, `total` all returned.
  * `206` — a page fetch failed mid-run after earlier rows had already committed. `partial: true`. Retry with the same `listId` to pick up remaining rows — already-imported leads will be rejected as duplicates.
  * `422` — the list was readable but zero leads could be imported: every row invalid, every row a duplicate, or a mix of the two with zero new inserts. The response body still contains the count breakdown.
  * `500` — failed to fetch any list rows, or every insert batch errored.

  **Partial success guard.** If pagination errors after some writes, the server returns `206` with `partial: true` rather than rolling back. Agents should surface this as "imported so far" in UI.

  **Dedup semantics.** Same as `addLeadsToCampaign` — the unique constraint is `(campaign_id, email)` for email campaigns and `(campaign_id, linkedin_url)` for LinkedIn campaigns.

  **Memory.** Paginated fetch + batched insert keeps memory bounded for large lists.
</Note>


## OpenAPI

````yaml post /api/campaigns/{id}/leads/import-from-list
openapi: 3.0.3
info:
  title: Puffle API
  version: 1.0.0
  description: >-
    HTTP API for the Puffle GTM platform - Feed and Lead Finder search
    preparation, campaign-backed Outbound execution, Puffle Agent runs, sender
    management, and Unibox reply workflows. Designed for operation by both
    humans and autonomous AI agents. Agents should start at the [Agent
    Playbook](/guides/agent-playbook) which prescribes a workspace-context check
    (`GET /api/context`) and core user journeys with exact call ordering.
  contact:
    name: Puffle Support
    url: https://puffle.ai
servers:
  - url: https://app.puffle.ai
    description: Production
security:
  - bearerAuth: []
tags:
  - name: Campaigns
    description: >-
      Campaign-backed Outbound execution. These endpoints manage draft,
      launching, active, paused, and completed Outbound runs with sequence
      nodes, contacts, and sender accounts.
  - name: Accounts
    description: Signed-in user account, settings, and workspace context endpoints.
  - name: Billing
    description: Billing customer portal and account billing endpoints.
  - name: Senders
    description: >-
      Connected sender accounts, email inboxes, sending domains, DNS
      verification, warmup, and sender capacity.
  - name: Socials
    description: >-
      Read connected LinkedIn and X accounts, review current and archived posts,
      and reconcile publication status. Creating, editing, scheduling,
      publishing, OAuth connection, analytics, and mentions remain
      dashboard-managed workflows and are not part of the public Bearer-token
      API.
paths:
  /api/campaigns/{id}/leads/import-from-list:
    post:
      tags:
        - Campaigns
      summary: Import Leads from List to Campaign
      description: >-
        Hydrates every person Lead in a user-owned List into campaign leads,
        paginating through canonical List memberships in batches.
      operationId: importLeadsFromListToCampaign
      parameters:
        - name: id
          in: path
          required: true
          schema:
            type: string
            description: Campaign UUID
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                listId:
                  type: string
                  format: uuid
                filter:
                  type: object
                  properties:
                    leadIds:
                      type: array
                      items:
                        type: string
                        minLength: 1
                    where:
                      type: array
                      items:
                        type: object
                        properties:
                          field:
                            type: string
                            minLength: 1
                          op:
                            type: string
                            enum:
                              - eq
                              - neq
                              - contains
                              - not_contains
                              - exists
                              - not_exists
                              - in
                              - not_in
                              - gt
                              - gte
                              - lt
                              - lte
                          value: {}
                        required:
                          - field
                          - op
                        additionalProperties: false
                    orderBy:
                      type: array
                      items:
                        type: object
                        properties:
                          field:
                            type: string
                            minLength: 1
                          direction:
                            type: string
                            enum:
                              - asc
                              - desc
                        required:
                          - field
                          - direction
                        additionalProperties: false
                    limit:
                      type: integer
                      minimum: 1
                      maximum: 5000
                  additionalProperties: false
              required:
                - listId
              additionalProperties: false
      responses:
        '200':
          description: Import succeeded with row-count breakdown.
          content:
            application/json:
              schema:
                type: object
                properties:
                  imported:
                    type: integer
                    minimum: 0
                    maximum: 9007199254740991
                  duplicates:
                    type: integer
                    minimum: 0
                    maximum: 9007199254740991
                  invalid:
                    type: integer
                    minimum: 0
                    maximum: 9007199254740991
                  errors:
                    type: integer
                    minimum: 0
                    maximum: 9007199254740991
                  total:
                    type: integer
                    minimum: 0
                    maximum: 9007199254740991
                  partial:
                    type: boolean
                required:
                  - imported
                  - duplicates
                  - invalid
                  - errors
                  - total
                additionalProperties: false
        '206':
          description: >-
            Partial success after some pages committed and a later page fetch
            failed.
          content:
            application/json:
              schema:
                type: object
                properties:
                  imported:
                    type: integer
                    minimum: 0
                    maximum: 9007199254740991
                  duplicates:
                    type: integer
                    minimum: 0
                    maximum: 9007199254740991
                  invalid:
                    type: integer
                    minimum: 0
                    maximum: 9007199254740991
                  errors:
                    type: integer
                    minimum: 0
                    maximum: 9007199254740991
                  total:
                    type: integer
                    minimum: 0
                    maximum: 9007199254740991
                  partial:
                    type: boolean
                required:
                  - imported
                  - duplicates
                  - invalid
                  - errors
                  - total
                additionalProperties: false
        '400':
          description: Missing list id or empty source list.
          content:
            application/json:
              schema:
                type: object
                properties:
                  error:
                    type: string
                required:
                  - error
                additionalProperties: false
        '401':
          description: Missing or invalid authentication.
          content:
            application/json:
              schema:
                type: object
                properties:
                  error:
                    type: string
                required:
                  - error
                additionalProperties: false
        '404':
          description: Campaign or list not found.
          content:
            application/json:
              schema:
                type: object
                properties:
                  error:
                    type: string
                required:
                  - error
                additionalProperties: false
        '422':
          description: Nothing importable because all rows were invalid and/or duplicates.
          content:
            application/json:
              schema:
                type: object
                properties:
                  error:
                    type: string
                required:
                  - error
                additionalProperties: false
        '500':
          description: Import failed before anything useful committed.
          content:
            application/json:
              schema:
                type: object
                properties:
                  error:
                    type: string
                required:
                  - error
                additionalProperties: false
components:
  securitySchemes:
    bearerAuth:
      type: http
      scheme: bearer
      bearerFormat: pk_live_...

````