---
title: "List leads"
method: GET
path: "/v1/leads"
tags: ["leads"]
---

# List leads

`GET /v1/leads`

## Request

- Base URL: `https://api.botdog.co`
- URL: `https://api.botdog.co/v1/leads`
- Auth: API key in header `x-api-key`

List leads for the team, with optional filters. Pass `linkedinUrl` to find the lead IDs for one LinkedIn profile — the usual first step before `DELETE /v1/leads/{id}` when a prospect has replied somewhere else.

## Query parameters

- `campaignId` string
- `linkedinUrl` string
- `listId` string
- `campaignStatus` 'CREATED' | 'ACTIVE' | 'PAUSED' | 'ERROR' | 'ARCHIVED' | 'COMPLETED'
- `replied` boolean
- `unread` boolean
- `skipped` boolean
- `skippedReason` 'DUPLICATE_IN_ANOTHER_CAMPAIGN_AT_IMPORT' | 'DUPLICATE_IN_ANOTHER_TEAM_CAMPAIGN_AT_IMPORT'
- `limit` number
- `cursor` string

## Response `200`

- PaginatedLeadsDto
  - `data` LeadSummaryDto[], required
    - `id` string, required: The unique identifier of the lead
    - `name` string, required: The name of the lead
    - `linkedinProfile` string, required: The LinkedIn profile URL of the lead
    - `company` string, nullable: The lead's company
    - `job` string, nullable: The lead's job title
    - `campaignId` string, nullable: The campaign this lead belongs to, if any
    - `listId` string, nullable: The list this lead belongs to, if any
    - `campaignStatus` string, nullable: The campaign's status when this lead was added to it. It is not updated as the lead moves through its sequence, so it does not show whether the lead's sequence is still running, has finished, failed or was stopped. For that, read the lead's `events` on GET /v1/leads/{id}: `WORKFLOW_CLEANUP` means the sequence finished, `WORKFLOW_FAILED` means it failed, and `stoppedAt` is set when it was stopped through the API.
    - `hasReplied` boolean, required: Whether the lead has replied
    - `hasUnreadReply` boolean, required: Whether the lead has an unread reply
    - `isSkipped` boolean, required: Whether the lead was skipped
    - `skippedReason` string, nullable: Why the lead was skipped, if applicable
    - `createdAt` string, date-time, required: When the lead was created
    - `invitedAt` string, date-time, nullable: When the invite was sent
    - `connectedAt` string, date-time, nullable: When the lead connected
    - `repliedAt` string, date-time, nullable: When the lead replied
    - `withdrawnAt` string, date-time, nullable: When the invitation was withdrawn
    - `stoppedAt` string, date-time, nullable: When the lead was stopped, if it was. This is the authoritative confirmation that a stop took effect: it is written only after the lead’s sequence has been torn down, so a non-null value means no further steps — including any message already waiting on a delay — can run. Poll this after DELETE /v1/leads/{id} rather than the `stopped` flag on the stop response.
  - `nextCursor` string, nullable, required: Opaque cursor for the next page; null when there are no more results. Pass it back as the `cursor` query parameter.

## Other responses

- `400`: `linkedinUrl` is not a LinkedIn profile URL
- `401`: Unauthorized. API key is missing or invalid.
- `403`: The key owner has no seat assigned (write endpoints only), the team is on Botdog Managed and so may only read (write endpoints only), or the subscription/plan does not permit this.
- `429`: Rate limit exceeded. Retry after cooldown.

---

[API](https://skmtc.dev/botdog/apis/botdog-api.md) · [All operations](https://skmtc.dev/botdog/apis/botdog-api/llms.txt) · [OpenAPI document](https://skmtc.dev/botdog/apis/botdog-api/revisions/6c0213d8a608?raw)
