---
title: "Add people to a sequence"
method: POST
path: "/sequences/{id}/leads"
tags: ["Leads"]
---

# Add people to a sequence

`POST /sequences/{id}/leads`

## Request

- Base URL: `https://app.pumpgtm.com/api/v1`
- URL: `https://app.pumpgtm.com/api/v1/sequences/{id}/leads`
- Auth: HTTP bearer

Queue people into one sequence. Nothing is sent in this call: people enter the paced engine and are contacted later inside working hours and account limits.

**Choose a method**

- `contacts`: 1 to 500 people, each with any mix of `linkedinUrl`, `email` and `xUsername`. Needs a connected LinkedIn account only when LinkedIn people go into a sequence with LinkedIn steps.
- `manual`: 1 to 500 people with LinkedIn URLs. Always needs a connected LinkedIn account.
- `csv`: CSV text with a header row, at most 500 rows. Always needs a connected LinkedIn account.
- `sales_navigator`: a saved Sales Navigator list URL. Imports in the background; poll `GET /leads/imports/{batchId}`. Always needs a connected LinkedIn account.

**How `contacts` routes people**

- Each person is queued only for the channels the sequence has steps for: connect steps are the LinkedIn lane, email steps the email lane, X DM or engage steps the X lane.
- A person with no identity for any of the sequence's channels is counted in `invalidSkipped` and not added.
- People already known by LinkedIn profile, email or X handle are counted in `duplicatesSkipped`.
- X handles are at most 15 characters. An X-only person becomes sendable once their handle has been resolved to an X account, which happens automatically shortly after the add.
- No paid lookups and no Energy charged.

**Approval and replay**

- Your request is the approval: a draft sequence is approved and started as part of the add. A paused sequence takes the people and stays paused.
- `requestId` is optional. Reusing it with the same body replays the stored result (`reused: true`); reusing it with a different body is refused.
- `expectedRevision` is optional on `contacts`. When given it must equal the sequence's current revision.

**Refusals (409, nothing added)**

`idempotency_conflict`, `sequence_not_active`, `sequence_not_ready`, `sequence_revision_conflict`, `linkedin_not_connected` (partners: complete a hosted connect link first) and the `lead_import_csv_*` mapping refusals, which carry `details`.

## Path parameters

- `id` string, uuid, required

## Headers

- `X-PumpGTM-Client` string, uuid
- `X-PumpGTM-User` string

## Request body

- union
  - object
    - `method` 'contacts', required
    - `requestId` string: Optional idempotency key; reuse it only to retry this exact request. Omitted means a fresh request.
    - `expectedRevision` integer: Optional. When given it must equal the sequence's current revision (409 sequence_revision_conflict otherwise); omitted means the current revision.
    - `leads` object[], required: 1 to 500 people, each with at least one of linkedinUrl, email or xUsername. A person is queued only for the channels the sequence has steps for; someone with no identity for any of its channels is counted in invalidSkipped.
      - `person` string, required
      - `company` string, nullable
      - `title` string, nullable
      - `linkedinUrl` string, nullable: Public LinkedIn /in/ profile URL.
      - `email` string, email, nullable
      - `xUsername` string, nullable: X handle (with or without @) or x.com profile URL.
  - object
    - `method` 'manual', required
    - `requestId` string: Optional idempotency key; reuse it only to retry this exact request. Omitted means a fresh request.
    - `leads` object[], required
      - `linkedinUrl` string, required
      - `person` string, nullable
      - `company` string, nullable
      - `title` string, nullable
      - `customFields` object: Per-person values from your own list, keyed by a lowercase token such as personalized_message; written verbatim wherever a message uses {{personalized_message}}.
  - object
    - `method` 'csv', required
    - `requestId` string: Optional idempotency key; reuse it only to retry this exact request. Omitted means a fresh request.
    - `csvContent` string, required: CSV with a header row; at most 500 rows and 100 columns. Person, LinkedIn URL, Company and Title columns are recognised by name.
    - `customColumns` object: Extra CSV header → lowercase token it fills, for example { "personalizedMessage": "personalized_message" }.
  - object
    - `method` 'sales_navigator', required
    - `requestId` string: Optional idempotency key; reuse it only to retry this exact request. Omitted means a fresh request.
    - `accountId` string: Connected LinkedIn account to import with; defaults to the workspace's account.
    - `listUrl` string, uri, required

## Response `201`

Successful response. Read outcome fields; success does not imply delivery.

- object
  - `addResult` object, required: contacts, manual and csv finish in this call (status "completed"). sales_navigator returns the initial import status instead; poll GET /leads/imports/{batchId}.
    - `method` 'contacts' | 'manual' | 'csv' | 'sales_navigator', required
    - `batchId` string, uuid, nullable
    - `status` string
    - `sequenceId` string, uuid, required
    - `sequenceStatus` 'active' | 'paused', required
    - `reused` boolean, required
    - `addedLeadIds` string[]
    - `addedLeads` object[]: manual and csv only.
      - `id` string, uuid, required
      - `person` string, nullable, required
      - `linkedinUrl` string, nullable, required
    - `summary` object
      - `submittedCount` integer, required
      - `addedCount` integer, required
      - `duplicatesSkipped` integer, required
      - `invalidSkipped` integer, required
      - `alreadyInvitedCount` integer, required
    - `contacted` unknown, required
    - `energyCharged` integer: contacts only; always 0.
  - `reviewUrl` string, required: Where the customer reviews or pauses the sequence.

## Other responses

- `400`: Invalid input; for partner keys also user_header_required when the account requires X-PumpGTM-User
- `401`: Missing, invalid or revoked key
- `403`: Workspace mismatch, channel or feature disabled; for partner keys also enterprise_required and user_disabled
- `404`: Resource unavailable in this workspace
- `409`: Revision, identity or state conflict: { error, message } and nothing changed
- `429`: Rate limit; respect Retry-After when provided
- `500`: internal_error: an unexpected failure on our side; retry, then contact PumpGTM
- `503`: Dependency unavailable; identity may be unknown

## Changes

- **2026-10-12** `06d2e4d0e84b`: 8 info
  - the response property `error` became required for the status `400`
  - the response property `error` became required for the status `401`
  - the response property `error` became required for the status `403`
  - the response property `error` became required for the status `404`
  - …4 more
- **2026-10-12** `08c80059d483`: 1 info
  - endpoint added

[Operation history](https://skmtc.dev/pumpgtm/apis/pumpgtm-api/changes/sequences/:id/leads/post.md)

---

[API](https://skmtc.dev/pumpgtm/apis/pumpgtm-api.md) - [All operations](https://skmtc.dev/pumpgtm/apis/pumpgtm-api/llms.txt) - [OpenAPI document](https://skmtc.dev/pumpgtm/apis/pumpgtm-api/revisions/06d2e4d0e84b?raw)
