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

# Stages

> Kanban board columns, including Won and Lost

Stages are the columns of the board. Each stage belongs to a pipeline and has a `position` that
defines its order. Every route on this page requires the `pipeline.manage` permission.

<Info>
  To create or reorder **several stages at once**, prefer
  [Configure a pipeline](/en/api-reference/pipeline/pipelines#configure-a-pipeline) — it is a
  transactional operation that saves the complete list.
</Info>

## The Stage object

<ResponseField name="id" type="string">
  Stage UUID
</ResponseField>

<ResponseField name="name" type="string">
  Name displayed at the top of the column
</ResponseField>

<ResponseField name="color" type="string">
  Color in the token format `"H S% L%"` (HSL triple without the `hsl()` wrapper)
</ResponseField>

<ResponseField name="kind" type="string">
  `won`, `lost`, or absent for a regular stage
</ResponseField>

<ResponseField name="position" type="integer">
  Column order on the board (0-based)
</ResponseField>

***

## Create a stage

<Card>
  <strong>POST</strong> `/backend/pipelines/{id}/stages`
</Card>

Adds a regular stage to the end of the pipeline. You cannot create `won` or `lost` stages —
they already exist from the moment the pipeline is created.

### Request Body

<ParamField body="name" type="string" required>
  Stage name
</ParamField>

<ParamField body="color" type="string">
  Color in the `"H S% L%"` format. When omitted, the default gray `"215 16% 47%"` is used.
</ParamField>

<RequestExample>
  ```bash cURL theme={null}
  curl -X POST "https://api.leavo.ai/backend/pipelines/bb0e8400-e29b-41d4-a716-446655440000/stages" \
    -H "Authorization: Bearer your_api_key_here" \
    -H "Content-Type: application/json" \
    -d '{ "name": "Proposal sent", "color": "271 81% 56%" }'
  ```

  ```javascript JavaScript theme={null}
  const response = await fetch(
    'https://api.leavo.ai/backend/pipelines/bb0e8400-e29b-41d4-a716-446655440000/stages',
    {
      method: 'POST',
      headers: {
        'Authorization': 'Bearer your_api_key_here',
        'Content-Type': 'application/json'
      },
      body: JSON.stringify({ name: 'Proposal sent', color: '271 81% 56%' })
    }
  );
  ```
</RequestExample>

<ResponseExample>
  ```json 201 Created theme={null}
  {
    "id": "cc4e8400-e29b-41d4-a716-446655440000",
    "name": "Proposal sent",
    "color": "271 81% 56%",
    "position": 4
  }
  ```
</ResponseExample>

***

## Update a stage

<Card>
  <strong>PUT</strong> `/backend/pipeline/stages/{id}`
</Card>

Renames, recolors or repositions a stage. Omitted fields stay unchanged.

### Request Body

<ParamField body="name" type="string">
  New name
</ParamField>

<ParamField body="color" type="string">
  New color in the `"H S% L%"` format
</ParamField>

<ParamField body="position" type="integer">
  New position on the board
</ParamField>

<Note>
  The `won` and `lost` stages can be renamed and recolored normally — it is the `kind` that
  does not change. This is how you replace the Portuguese default names (`Ganho`, `Perdido`)
  with English ones.
</Note>

<RequestExample>
  ```bash cURL theme={null}
  curl -X PUT "https://api.leavo.ai/backend/pipeline/stages/cc4e8400-e29b-41d4-a716-446655440000" \
    -H "Authorization: Bearer your_api_key_here" \
    -H "Content-Type: application/json" \
    -d '{ "name": "Proposal", "position": 2 }'
  ```
</RequestExample>

***

## Delete a stage

<Card>
  <strong>DELETE</strong> `/backend/pipeline/stages/{id}`
</Card>

### Query Parameters

<ParamField query="target_stage_id" type="string">
  Stage that will receive the deals from the deleted stage. **Required** when the stage still
  contains deals.
</ParamField>

<Warning>
  Deleting a stage that still has deals **without** `target_stage_id` returns **409**. Deals are
  never removed along with the stage — the API forces you to pick a destination.
</Warning>

The destination must belong to the same pipeline and cannot be the stage being deleted —
both cases return **400**.

<Warning>
  The **Won** (`kind: "won"`) and **Lost** (`kind: "lost"`) stages **cannot be deleted**
  (**400**), because there is no route that recreates them. The pipeline must also keep at
  least one stage.
</Warning>

<RequestExample>
  ```bash cURL theme={null}
  # Empty stage — no destination needed
  curl -X DELETE "https://api.leavo.ai/backend/pipeline/stages/cc4e8400-e29b-41d4-a716-446655440000" \
    -H "Authorization: Bearer your_api_key_here"

  # Stage with deals — destination required
  curl -X DELETE "https://api.leavo.ai/backend/pipeline/stages/cc4e8400-e29b-41d4-a716-446655440000?target_stage_id=cc0e8400-e29b-41d4-a716-446655440000" \
    -H "Authorization: Bearer your_api_key_here"
  ```
</RequestExample>

<ResponseExample>
  ```json 200 OK theme={null}
  { "success": true }
  ```

  ```json 409 Conflict theme={null}
  {
    "code": "ERR_CONFLICT",
    "message": "A etapa \"Proposta enviada\" tem 12 negócio(s). Escolha para qual etapa eles devem ir."
  }
  ```

  ```json 400 Bad Request theme={null}
  {
    "code": "ERR_INVALID_INPUT",
    "message": "A etapa de ganho e a de perda não podem ser excluídas — a pipeline precisa delas para marcar negócios como ganhos ou perdidos"
  }
  ```
</ResponseExample>

<Note>
  Error `message` strings are returned by the API in Portuguese. Match on `code`
  (`ERR_CONFLICT`, `ERR_INVALID_INPUT`), never on the message text.
</Note>

<Tip>
  Recommended interface flow: try the `DELETE` without `target_stage_id`; if you get **409**,
  ask the user where the deals should go and retry with the parameter.
</Tip>
