> ## 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.

# Negócios

> Quadro, listagem, criação, edição e movimentação de negócios

Um **negócio** (deal) é uma oportunidade dentro de uma etapa. Ele sempre aponta para um Lead
real — os dados de contato vêm do Lead, não são copiados.

## O objeto Negócio

<ResponseField name="id" type="string">
  UUID do negócio
</ResponseField>

<ResponseField name="number" type="integer">
  Número sequencial legível do negócio (ex: `1042`)
</ResponseField>

<ResponseField name="pipeline_id" type="string">
  UUID da pipeline
</ResponseField>

<ResponseField name="stage_id" type="string">
  UUID da etapa atual
</ResponseField>

<ResponseField name="lead_id" type="string">
  UUID do Lead vinculado
</ResponseField>

<ResponseField name="owner_id" type="string">
  UUID do usuário responsável, ou `null`
</ResponseField>

<ResponseField name="value" type="number">
  Valor manual do negócio. Só é usado quando o negócio **não tem produtos**.
</ResponseField>

<ResponseField name="total" type="number">
  Total calculado: soma de `price × qty` dos produtos, ou `value` quando não há produtos
</ResponseField>

<ResponseField name="origin" type="string">
  Origem do negócio (`manual` por padrão)
</ResponseField>

<ResponseField name="loss_reason" type="string">
  Motivo da perda. Presente apenas em negócios perdidos.
</ResponseField>

<ResponseField name="note" type="string">
  Observação livre
</ResponseField>

<ResponseField name="won_at" type="string">
  Data em que entrou na etapa de ganho (ISO 8601)
</ResponseField>

<ResponseField name="lost_at" type="string">
  Data em que entrou na etapa de perda (ISO 8601)
</ResponseField>

<ResponseField name="lead_name" type="string">
  Nome do Lead vinculado (resolvido na leitura)
</ResponseField>

<ResponseField name="lead_surname" type="string">
  Sobrenome do Lead
</ResponseField>

<ResponseField name="lead_company" type="string">
  Empresa do Lead
</ResponseField>

<ResponseField name="lead_email" type="string">
  Email do Lead
</ResponseField>

<ResponseField name="lead_phone" type="string">
  Telefone do Lead
</ResponseField>

<ResponseField name="lead_avatar" type="string">
  URL do avatar do Lead
</ResponseField>

<ResponseField name="lead_status_id" type="string">
  UUID do status do Lead
</ResponseField>

<ResponseField name="products" type="DealProduct[]">
  Linhas de produto do negócio
</ResponseField>

<ResponseField name="tags" type="Tag[]">
  Tags do negócio — reutilizam o mesmo catálogo de tags dos Leads
</ResponseField>

<ResponseField name="pending_todos" type="integer">
  Quantidade de atividades pendentes
</ResponseField>

<ResponseField name="overdue_todos" type="integer">
  Quantidade de atividades pendentes e atrasadas
</ResponseField>

***

## Quadro (board)

<Card>
  <strong>GET</strong> `/backend/pipelines/{id}/board`
</Card>

Retorna os **metadados do quadro**: a pipeline com suas etapas e, por coluna, a contagem de
negócios e o total em dinheiro. Não retorna os negócios em si — use
[Listar negócios](#listar-negócios) para carregar cada coluna.

### Query Parameters

<ParamField query="search" type="string">
  Busca pelo **número do negócio** ou pelo **nome/empresa do Lead** vinculado
</ParamField>

<ParamField query="stage_id" type="string">
  Restringe a uma etapa específica
</ParamField>

<ParamField query="sort" type="string" default="recent">
  `recent` (mais novos primeiro) ou `oldest`
</ParamField>

<ParamField query="mode" type="string" default="created">
  Qual data o filtro de período considera: `created`, `won` ou `lost`
</ParamField>

<ParamField query="period" type="string">
  `7d`, `30d`, `1y` ou `custom`. Com `custom`, informe também `from` e `to`.
</ParamField>

<ParamField query="from" type="string">
  Início do período (ISO 8601). Usado apenas com `period=custom`.
</ParamField>

<ParamField query="to" type="string">
  Fim do período (ISO 8601). Usado apenas com `period=custom`.
</ParamField>

<ResponseExample>
  ```json 200 OK theme={null}
  {
    "pipeline": {
      "id": "bb0e8400-e29b-41d4-a716-446655440000",
      "group_id": "aa0e8400-e29b-41d4-a716-446655440000",
      "name": "Vendas Inbound",
      "description": "Leads vindos do site",
      "position": 0,
      "stages": [
        { "id": "cc0e8400-e29b-41d4-a716-446655440000", "name": "Entrada", "color": "217 91% 60%", "position": 0 }
      ],
      "loss_reasons": ["Sem orçamento"],
      "created_at": "2026-07-16T09:00:00Z"
    },
    "stages": [
      {
        "stage": { "id": "cc0e8400-e29b-41d4-a716-446655440000", "name": "Entrada", "color": "217 91% 60%", "position": 0 },
        "deal_count": 12,
        "total": 48500.00
      }
    ],
    "total_deals": 12,
    "total_amount": 48500.00
  }
  ```
</ResponseExample>

***

## Listar negócios

<Card>
  <strong>GET</strong> `/backend/pipelines/{id}/deals`
</Card>

Retorna uma página de negócios. O quadro pagina **por coluna** — passe `stage_id` para carregar
uma etapa de cada vez em vez de toda a pipeline.

### Query Parameters

Aceita todos os filtros do [quadro](#quadro-board), mais:

<ParamField query="page" type="integer" default="1">
  Página desejada
</ParamField>

<ParamField query="limit" type="integer" default="20">
  Itens por página. Valores fora de 1–100 voltam ao padrão de 20.
</ParamField>

<RequestExample>
  ```bash cURL theme={null}
  curl -X GET "https://api.leavo.ai/backend/pipelines/bb0e8400-e29b-41d4-a716-446655440000/deals?stage_id=cc0e8400-e29b-41d4-a716-446655440000&limit=20" \
    -H "Authorization: Bearer sua_chave_aqui"
  ```

  ```javascript JavaScript theme={null}
  const params = new URLSearchParams({
    stage_id: 'cc0e8400-e29b-41d4-a716-446655440000',
    limit: '20'
  });

  const response = await fetch(
    `https://api.leavo.ai/backend/pipelines/bb0e8400-e29b-41d4-a716-446655440000/deals?${params}`,
    { headers: { 'Authorization': 'Bearer sua_chave_aqui' } }
  );
  ```
</RequestExample>

<ResponseExample>
  ```json 200 OK theme={null}
  {
    "data": [
      {
        "id": "dd0e8400-e29b-41d4-a716-446655440000",
        "number": 1042,
        "pipeline_id": "bb0e8400-e29b-41d4-a716-446655440000",
        "stage_id": "cc0e8400-e29b-41d4-a716-446655440000",
        "lead_id": "550e8400-e29b-41d4-a716-446655440000",
        "owner_id": null,
        "value": 0,
        "total": 4500.00,
        "origin": "manual",
        "note": "",
        "created_at": "2026-07-16T09:30:00Z",
        "updated_at": "2026-07-16T09:30:00Z",
        "lead_name": "João Silva",
        "lead_company": "Empresa XYZ",
        "lead_email": "joao@exemplo.com",
        "lead_phone": "+5511999999999",
        "products": [
          {
            "id": "ee0e8400-e29b-41d4-a716-446655440000",
            "product_id": "ff0e8400-e29b-41d4-a716-446655440000",
            "name": "Plano Premium",
            "price": 1500.00,
            "qty": 3,
            "custom": false,
            "total": 4500.00
          }
        ],
        "tags": [],
        "pending_todos": 1,
        "overdue_todos": 0
      }
    ],
    "pagination": {
      "current_page": 1,
      "total_pages": 1,
      "total_count": 12,
      "has_next": false,
      "has_prev": false
    }
  }
  ```
</ResponseExample>

***

## Obter um negócio

<Card>
  <strong>GET</strong> `/backend/pipeline/deals/{id}`
</Card>

Retorna o negócio completo, com produtos, tags e dados do Lead.

***

## Criar negócio

<Card>
  <strong>POST</strong> `/backend/pipeline/deals`
</Card>

Requer a permissão `pipeline.deals.create`.

### Request Body

<ParamField body="pipeline_id" type="string" required>
  UUID da pipeline
</ParamField>

<ParamField body="stage_id" type="string" required>
  UUID da etapa inicial. Precisa pertencer à pipeline informada, senão a resposta é **400**.
</ParamField>

<ParamField body="lead_id" type="string">
  UUID de um Lead existente
</ParamField>

<ParamField body="new_lead" type="object">
  Dados para criar um Lead novo junto com o negócio
</ParamField>

<Expandable title="Propriedades de new_lead">
  <ParamField body="name" type="string" required>
    Nome do lead
  </ParamField>

  <ParamField body="phone" type="string" required>
    Telefone do lead
  </ParamField>

  <ParamField body="email" type="string">
    Email do lead
  </ParamField>

  <ParamField body="company" type="string">
    Empresa do lead
  </ParamField>
</Expandable>

<Warning>
  Informe **`lead_id` ou `new_lead`**. Sem nenhum dos dois, a resposta é **400** — um negócio
  nunca existe sem um Lead.
</Warning>

<ParamField body="owner_id" type="string">
  UUID do usuário responsável
</ParamField>

<ParamField body="loss_reason" type="string">
  Motivo da perda. **Obrigatório** quando `stage_id` aponta para a etapa de perda.
</ParamField>

<ParamField body="lead_status_id" type="string">
  Status a aplicar no Lead vinculado
</ParamField>

<ParamField body="products" type="DealProduct[]">
  Linhas de produto do negócio
</ParamField>

<Expandable title="Propriedades de uma linha de produto">
  <ParamField body="product_id" type="string">
    UUID de um produto do catálogo. Nome e preço são copiados no momento da inclusão.
  </ParamField>

  <ParamField body="name" type="string">
    Nome da linha avulsa. Obrigatório quando `custom` é `true`.
  </ParamField>

  <ParamField body="price" type="number">
    Preço unitário. Não pode ser negativo.
  </ParamField>

  <ParamField body="qty" type="integer">
    Quantidade. Valores menores que 1 são tratados como 1.
  </ParamField>

  <ParamField body="custom" type="boolean">
    `true` para uma linha avulsa, que existe só neste negócio e não entra no catálogo global
  </ParamField>
</Expandable>

<ParamField body="tag_ids" type="string[]">
  UUIDs de tags a associar
</ParamField>

<ParamField body="origin" type="string">
  Origem do negócio. Padrão: `manual`.
</ParamField>

<RequestExample>
  ```bash cURL theme={null}
  curl -X POST "https://api.leavo.ai/backend/pipeline/deals" \
    -H "Authorization: Bearer sua_chave_aqui" \
    -H "Content-Type: application/json" \
    -d '{
      "pipeline_id": "bb0e8400-e29b-41d4-a716-446655440000",
      "stage_id": "cc0e8400-e29b-41d4-a716-446655440000",
      "lead_id": "550e8400-e29b-41d4-a716-446655440000",
      "products": [
        { "product_id": "ff0e8400-e29b-41d4-a716-446655440000", "qty": 3 },
        { "custom": true, "name": "Implantação", "price": 800.00, "qty": 1 }
      ],
      "tag_ids": ["880e8400-e29b-41d4-a716-446655440000"]
    }'
  ```

  ```javascript JavaScript theme={null}
  const response = await fetch('https://api.leavo.ai/backend/pipeline/deals', {
    method: 'POST',
    headers: {
      'Authorization': 'Bearer sua_chave_aqui',
      'Content-Type': 'application/json'
    },
    body: JSON.stringify({
      pipeline_id: 'bb0e8400-e29b-41d4-a716-446655440000',
      stage_id: 'cc0e8400-e29b-41d4-a716-446655440000',
      new_lead: {
        name: 'Maria Souza',
        phone: '+5511988887777',
        company: 'ACME'
      }
    })
  });
  ```
</RequestExample>

Retorna **201 Created** com o negócio.

***

## Atualizar negócio

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

Requer `pipeline.deals.edit`. Campos omitidos permanecem inalterados.

### Request Body

<ParamField body="owner_id" type="string">
  Novo responsável
</ParamField>

<ParamField body="value" type="number">
  Valor manual. Não pode ser negativo. Só afeta o `total` quando o negócio não tem produtos.
</ParamField>

<ParamField body="note" type="string">
  Observação
</ParamField>

<ParamField body="origin" type="string">
  Origem
</ParamField>

<ParamField body="products" type="DealProduct[]">
  Quando enviado, **substitui a lista inteira** de produtos. Envie `[]` para remover todos.
</ParamField>

<Note>
  A etapa **não** é alterada por este endpoint. Use [Mover de etapa](#mover-de-etapa).
</Note>

***

## Mover de etapa

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

Move o negócio entre colunas do quadro. Requer `pipeline.deals.edit`.

### Request Body

<ParamField body="stage_id" type="string" required>
  UUID da etapa de destino. Precisa pertencer à mesma pipeline do negócio, senão a resposta é
  **400**.
</ParamField>

<ParamField body="loss_reason" type="string">
  Motivo da perda. **Obrigatório** quando a etapa de destino tem `kind: "lost"`.
</ParamField>

<Warning>
  Mover para a etapa de perda **sem** `loss_reason` retorna **400**. Não existe caminho que
  perca um negócio em silêncio.
</Warning>

Efeitos colaterais da movimentação. Cada movimento **sempre limpa `won_at` e `lost_at` antes**
de aplicar o destino, então tirar um negócio de Ganho/Perdido descarta a marcação junto:

| Destino        | Efeito                                                       |
| -------------- | ------------------------------------------------------------ |
| `kind: "won"`  | Preenche `won_at`; `lost_at` e `loss_reason` ficam nulos     |
| `kind: "lost"` | Preenche `lost_at` e grava `loss_reason`; `won_at` fica nulo |
| Etapa comum    | `won_at`, `lost_at` e `loss_reason` ficam nulos              |

O motivo pode ser um dos `loss_reasons` configurados na pipeline ou um texto livre — a opção
"Outro" não fica armazenada na lista de motivos.

<RequestExample>
  ```bash cURL theme={null}
  curl -X PUT "https://api.leavo.ai/backend/pipeline/deals/dd0e8400-e29b-41d4-a716-446655440000/stage" \
    -H "Authorization: Bearer sua_chave_aqui" \
    -H "Content-Type: application/json" \
    -d '{
      "stage_id": "cc3e8400-e29b-41d4-a716-446655440000",
      "loss_reason": "Fechou com concorrente"
    }'
  ```
</RequestExample>

<ResponseExample>
  ```json 400 Bad Request theme={null}
  {
    "code": "ERR_INVALID_INPUT",
    "message": "Informe o motivo da perda para marcar o negócio como perdido"
  }
  ```
</ResponseExample>

***

## Tags do negócio

As tags do negócio reutilizam o mesmo catálogo de tags dos Leads — não há um catálogo separado.

### Adicionar tag

<Card>
  <strong>POST</strong> `/backend/pipeline/deals/{id}/tags/{tagID}`
</Card>

### Remover tag

<Card>
  <strong>DELETE</strong> `/backend/pipeline/deals/{id}/tags/{tagID}`
</Card>

Ambas exigem `pipeline.deals.edit` e retornam `{ "success": true }`.

***

## Excluir negócio

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

Requer `pipeline.deals.delete`.

<Warning>
  Exclui o negócio e tudo que pende dele: produtos, tags, atividades, arquivos e histórico.
  O **Lead vinculado não é excluído**.
</Warning>

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