# Retrieve the pipeline

`GET /v1/campaigns/{campaign_id}/pipeline`

Returns the campaign's pipelines with every stage in board order and how many of the campaign's leads are in each.

**Scope:** `leads:read`

The board is always the campaign's own. A pipeline can be shared by several campaigns: the board lists every stage of the pipeline but counts only this campaign's cards, never another campaign's leads on the same pipeline. Archived cards are not counted, as in DialEcho.

The default pipeline (the one `POST /v1/leads` adds new leads to) comes first, then the campaign's other pipelines in the order they were added to it, for example a follow-through pipeline won deals move into. If the member's role only lets them open some pipelines, only those are listed. A lead whose deal moved into a follow-through pipeline has a card on both boards and is counted on both.

`lead_count` is one database count per stage, so the board costs the same for 20 leads or 20,000. It counts every card of the campaign in the stage, including leads the member cannot see, cards they may not open and cards whose lead was deleted, so the stage's lead list can be shorter. The board never contains names, contact details or deal values.

The campaign must be one the key may reach, otherwise `404`.

## Path parameters

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `campaign_id` | `UUID` | Yes | A campaign the key may reach. |

## Response

**Status:** `200 OK`

| Name | Type | Description |
| --- | --- | --- |
| `campaign_id` | `UUID` | The campaign. |
| `pipelines` | `array of objects` | The campaign's pipelines, default first. Empty when it has none yet or the member may open none. |
| `pipelines.id` | `UUID` | The pipeline. Pass it as `pipeline_id` to list a stage of a pipeline that is not the default. |
| `pipelines.name` | `string \| null` | The pipeline's name. |
| `pipelines.is_default` | `boolean` | `true` for the campaign's default pipeline, where new leads are added. |
| `pipelines.stages` | `array of objects` | Every stage in board order (left to right), including empty ones. |
| `pipelines.stages.slug` | `string` | The stage slug, as `card.stage` and stage moves use it. Unique within its pipeline only: two pipelines can both have a `new` stage. |
| `pipelines.stages.name` | `string \| null` | The stage name on the board. |
| `pipelines.stages.outcome` | `string` | The outcome set for the stage in DialEcho, whatever it is called. One of `open`, `won`, `lost`. |
| `pipelines.stages.position` | `integer` | Position on the board as stored; positions can skip numbers. |
| `pipelines.stages.lead_count` | `integer` | How many of the campaign's cards are in the stage now. |

## Example request

**curl**

```bash
curl "https://development.agencydevworks.ai/v1/campaigns/cccccccc-0000-4000-8000-000000000001/pipeline" \
  -H "Authorization: Bearer dei_your_key"
```

**JavaScript**

```js
const response = await fetch("https://development.agencydevworks.ai/v1/campaigns/cccccccc-0000-4000-8000-000000000001/pipeline", {
  headers: {
    "Authorization": "Bearer dei_your_key",
  },
});
const data = await response.json();
```

## Example response

**Status:** `200 OK`

```json
{
  "campaign_id": "cccccccc-0000-4000-8000-000000000001",
  "pipelines": [
    {
      "id": "eeeeeeee-0000-4000-8000-000000000001",
      "name": "Sales",
      "is_default": true,
      "stages": [
        { "slug": "new", "name": "New", "outcome": "open", "position": 0, "lead_count": 42 },
        { "slug": "contacted", "name": "Contacted", "outcome": "open", "position": 1, "lead_count": 23 },
        { "slug": "appointment", "name": "Appointment Set", "outcome": "open", "position": 2, "lead_count": 17 },
        { "slug": "won", "name": "Won", "outcome": "won", "position": 3, "lead_count": 5 },
        { "slug": "lost", "name": "Lost", "outcome": "lost", "position": 4, "lead_count": 9 }
      ]
    },
    {
      "id": "eeeeeeee-0000-4000-8000-000000000002",
      "name": "Fulfillment",
      "is_default": false,
      "stages": [
        { "slug": "new", "name": "Kickoff", "outcome": "open", "position": 0, "lead_count": 3 },
        { "slug": "done", "name": "Delivered", "outcome": "open", "position": 1, "lead_count": 2 }
      ]
    }
  ]
}
```

## Errors

| HTTP | Code | When |
| --- | --- | --- |
| 403 | `insufficient_scope` | The key does not have `leads:read`. |
| 404 | `not_found` | The campaign does not exist or the key cannot reach it. |
| 422 | `invalid_request` | `campaign_id` is not a UUID. |
| 503 | `dependency_unavailable` | The report or the access check is temporarily unavailable. Retry the same request with backoff. |

Every endpoint can also answer `401 invalid_api_key`, `429 rate_limited` and `503 dependency_unavailable`. See [Errors](/api/#errors) in the overview.

## Related endpoints

- `GET /v1/campaigns/{campaign_id}/pipeline/stages/{stage}/leads` · [List a stage's leads](/api/reporting/stage-leads)
- `PUT /v1/leads/{lead_id}/stage` · [Move a lead's card](/api/leads/move-stage)
- `GET /v1/campaigns/{campaign_id}/conversions` · [List conversions](/api/reporting/list-conversions)
