> For the complete documentation index, see [llms.txt](https://docs.sprinthub.com/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.sprinthub.com/topicos/api/api-listar-oportunidades-do-funil-com-filtros-e-paginacao.md).

# API - Listar Oportunidades do Funil com Filtros e Paginação

Complementa a página [API - Chamada API para Listar Oportunidades de um Lead](/topicos/api/api-chamada-api-para-listar-oportunidades-de-um-lead.md). Enquanto aquele endpoint retorna todas as oportunidades de **um lead específico**, este retorna as oportunidades de **um funil inteiro**, com filtros, ordenação implícita do Kanban, paginação e, principalmente, a possibilidade de paginar **coluna por coluna (etapa por etapa)** através do parâmetro `columnId`.

É o mesmo endpoint que a interface do CRM usa para montar o Kanban: cada coluna carrega sua própria página de cards, de forma independente das demais.

### Listar oportunidades de um funil

**`POST`** `/crm/opportunities/{funnelId}?i=suainstancia&apitoken=xxxxxx`

`{funnelId}` = ID do funil (CRM). No exemplo abaixo, `8`.

Endpoint completo: `https://sprinthub-api-master.sprinthub.app/crm/opportunities/8?i=suainstancia&apitoken=xxxxxx`

> **Base da API.** `https://sprinthub-api-master.sprinthub.app` é a URL base. Substitua `suainstancia` pelo nome da sua instância, o mesmo que aparece na URL do painel, e `xxxxxx` pela sua chave de API.

#### Parâmetros de URL

| Parâmetro  | Obrigatório | Descrição                                      |
| ---------- | ----------- | ---------------------------------------------- |
| `i`        | Sim         | Nome da instância. Exemplo: `?i=suainstancia`. |
| `apitoken` | Sim         | Chave de API da instância.                     |

#### Headers

| Name         | Value              |
| ------------ | ------------------ |
| Content-Type | `application/json` |

As oportunidades retornadas respeitam as permissões vinculadas à chave de API (Departamentos, Grupos de Permissões e permissões do funil).

***

### Antes de começar: descobrindo o `funnelId` e o `columnId`

O `funnelId` da URL é o ID do CRM (funil). Para listar todos os funis da instância em uma única chamada GET:

```bash
curl --location 'https://sprinthub-api-master.sprinthub.app/crm?i=suainstancia&apitoken=xxxxxx'
```

Cada funil retornado traz seu ID, que é o valor usado em `/crm/opportunities/{funnelId}`, e as etapas do funil, cujos IDs alimentam o parâmetro `columnId` do corpo da requisição.

Os IDs de etapa também aparecem no campo `crm_column` de cada oportunidade retornada por este endpoint, o que serve como conferência rápida.

### Corpo da requisição

```json
{
    "filterByUsers": [],
    "filterByStatus": ["open"],
    "filterByCreateDate": null,
    "filterByExpectedCloseDate": null,
    "filters": [],
    "search": "",
    "searchBy": "lead",
    "page": 5,
    "limit": 25,
    "columnId": 58,
    "onlyArchived": false
}
```

#### Referência dos parâmetros

| Parâmetro                   | Tipo              | Padrão   | Descrição                                                                                                            |
| --------------------------- | ----------------- | -------- | -------------------------------------------------------------------------------------------------------------------- |
| `filterByUsers`             | array de inteiros | `[]`     | IDs dos usuários responsáveis pelas oportunidades. Vazio retorna todos os responsáveis visíveis para a sessão.       |
| `filterByStatus`            | array de strings  | `[]`     | Status das oportunidades: `open`, `gain`, `lost`. Aceita mais de um. Vazio retorna todos.                            |
| `filterByCreateDate`        | objeto ou `null`  | `null`   | Período de criação da oportunidade. `null` desliga o filtro.                                                         |
| `filterByExpectedCloseDate` | objeto ou `null`  | `null`   | Período de fechamento previsto. `null` desliga o filtro.                                                             |
| `filters`                   | array de objetos  | `[]`     | Filtros avançados (condições combinadas sobre campos da oportunidade, do lead e da empresa). Vazio desliga o filtro. |
| `search`                    | string            | `""`     | Termo de busca textual. Vazio desliga a busca.                                                                       |
| `searchBy`                  | string            | `"lead"` | Define onde o termo de `search` é aplicado. `lead` busca pelos dados do contato vinculado à oportunidade.            |
| `page`                      | inteiro           | `1`      | Página desejada. A primeira página é `1`.                                                                            |
| `limit`                     | inteiro           | `25`     | Quantidade de oportunidades por página.                                                                              |
| `columnId`                  | inteiro           | -        | ID da coluna (etapa) do funil. Restringe o resultado a uma única etapa e pagina apenas dentro dela.                  |
| `onlyArchived`              | booleano          | `false`  | `true` retorna somente oportunidades arquivadas. `false` retorna somente as não arquivadas.                          |

#### Detalhamento dos filtros

**`filterByUsers`**

Filtra pelo responsável da oportunidade. Corresponde ao filtro **Responsável** da interface.

```json
"filterByUsers": [12, 47]
```

Retorna oportunidades cujo responsável seja o usuário 12 ou o 47. O array vazio não significa "nenhum responsável": significa "sem filtro por responsável".

**`filterByStatus`**

Corresponde ao filtro **Status**.

| Valor  | Significado            |
| ------ | ---------------------- |
| `open` | Oportunidade em aberto |
| `gain` | Oportunidade ganha     |
| `lost` | Oportunidade perdida   |

```json
"filterByStatus": ["gain", "lost"]
```

> **Atenção.** A visualização de oportunidades ganhas e perdidas depende da permissão **CRM - Oportunidades Ganhas e Perdidas** do grupo do usuário. Se a chave de API não tiver essa permissão, o filtro não trará esses registros.

**`filterByCreateDate` e `filterByExpectedCloseDate`**

Filtram por período: data de criação da oportunidade e data de fechamento previsto, respectivamente. Correspondem aos filtros **Data de criação** e **Data de fechamento esperada** da interface.

```json
"filterByCreateDate": {
    "start": "2026-08-01",
    "end": "2026-08-31"
}
```

Enviar `null` (ou omitir) desliga o filtro. Os dois filtros são independentes e podem ser combinados na mesma requisição.

**`filters`**

Recebe os **Filtros Avançados** do CRM: condições montadas sobre campos da oportunidade, do lead ou da empresa, inclusive campos personalizados. Cada item do array representa uma condição, e as condições são combinadas entre si.

```json
"filters": [
    {
        "field": "custom_field_id_ou_nome",
        "operator": "equals",
        "value": "Plano Premium"
    }
]
```

A forma mais segura de descobrir a estrutura exata de uma condição é montá-la na interface do CRM e inspecionar o corpo da requisição enviada pelo navegador. O array vazio equivale a "sem filtros avançados".

**`search` e `searchBy`**

`search` é o termo digitado. `searchBy` define o alvo da busca. Com `searchBy: "lead"`, o termo é comparado com os dados do contato vinculado à oportunidade (nome, telefone, e-mail), e não com o título do card.

```json
"search": "maria",
"searchBy": "lead"
```

`search` vazio ignora `searchBy`.

**`onlyArchived`**

Alterna entre as duas visões da base. Não existe visão combinada: ou a requisição traz arquivadas, ou traz não arquivadas.

```json
"onlyArchived": true
```

***

### Paginação por coluna do funil

Este é o ponto central deste endpoint. O CRM não pagina o funil como uma lista única: cada coluna do Kanban é uma sequência de páginas própria.

* Com `columnId` preenchido, `page` e `limit` navegam **apenas dentro daquela etapa**. `page: 5` com `limit: 25` retorna as oportunidades da 101ª à 125ª posição **daquela coluna**, na ordem em que aparecem no Kanban.
* Sem `columnId`, `page` e `limit` navegam pelo funil inteiro, misturando as etapas.
* Os filtros são aplicados **antes** da paginação. Mudar qualquer filtro reinicia a contagem: volte para `page: 1`.
* O fim da coluna é detectado quando a resposta traz menos itens do que o `limit` solicitado, ou quando traz um array vazio.

#### Exemplo: quinta página da coluna 58

```bash
curl --location 'https://sprinthub-api-master.sprinthub.app/crm/opportunities/8?i=suainstancia&apitoken=xxxxxx' \
--header 'Content-Type: application/json' \
--data '{
    "filterByUsers": [],
    "filterByStatus": ["open"],
    "filterByCreateDate": null,
    "filterByExpectedCloseDate": null,
    "filters": [],
    "search": "",
    "searchBy": "lead",
    "page": 5,
    "limit": 25,
    "columnId": 58,
    "onlyArchived": false
}'
```

#### Exemplo: funil inteiro, sem separar por etapa

Basta omitir `columnId`.

```bash
curl --location 'https://sprinthub-api-master.sprinthub.app/crm/opportunities/8?i=suainstancia&apitoken=xxxxxx' \
--header 'Content-Type: application/json' \
--data '{
    "filterByUsers": [],
    "filterByStatus": ["open"],
    "filterByCreateDate": null,
    "filterByExpectedCloseDate": null,
    "filters": [],
    "search": "",
    "searchBy": "lead",
    "page": 1,
    "limit": 50,
    "onlyArchived": false
}'
```

#### Exemplo: ganhas no mês, de dois vendedores, em uma etapa

```bash
curl --location 'https://sprinthub-api-master.sprinthub.app/crm/opportunities/8?i=suainstancia&apitoken=xxxxxx' \
--header 'Content-Type: application/json' \
--data '{
    "filterByUsers": [12, 47],
    "filterByStatus": ["gain"],
    "filterByCreateDate": {
        "start": "2026-08-01",
        "end": "2026-08-31"
    },
    "filterByExpectedCloseDate": null,
    "filters": [],
    "search": "",
    "searchBy": "lead",
    "page": 1,
    "limit": 25,
    "columnId": 58,
    "onlyArchived": false
}'
```

#### Exemplo: varrer uma coluna inteira

```javascript
async function listarColunaCompleta(funnelId, columnId, apitoken, instancia) {
  const base = `https://sprinthub-api-master.sprinthub.app/crm/opportunities/${funnelId}?i=${instancia}&apitoken=${apitoken}`;
  const limit = 50;
  let page = 1;
  const todas = [];

  while (true) {
    const res = await fetch(base, {
      method: "POST",
      headers: {
        "Content-Type": "application/json",
      },
      body: JSON.stringify({
        filterByUsers: [],
        filterByStatus: ["open"],
        filterByCreateDate: null,
        filterByExpectedCloseDate: null,
        filters: [],
        search: "",
        searchBy: "lead",
        page,
        limit,
        columnId,
        onlyArchived: false,
      }),
    });

    const pagina = await res.json();
    const itens = Array.isArray(pagina) ? pagina : pagina.opportunities || [];

    todas.push(...itens);
    if (itens.length < limit) break;
    page++;
  }

  return todas;
}
```

Para varrer o funil inteiro etapa por etapa, execute a função acima em laço sobre os IDs das colunas do funil. Essa é a forma recomendada de exportar grandes volumes: cada coluna é uma sequência menor e mais estável do que uma paginação única sobre o funil todo, que sofre deslocamento sempre que um card muda de etapa durante a varredura.

***

### Respostas

#### 200 OK

```json
[
    {
        "id": 4533,
        "title": "Test Oportunidade",
        "value": "1.00",
        "crm_column": 58,
        "lead_id": 8473,
        "sequence": 2
        ...
    }
]
```

Cada item traz `crm_column` igual ao `columnId` solicitado, quando o filtro por coluna é usado.

#### 400 Bad Request

```json
{
    "error": "Invalid request"
}
```

Corpo malformado ou `funnelId` inexistente.

#### 401 Unauthorized

```json
{
    "error": "Unauthorized"
}
```

`apitoken` ausente, inválido ou sem permissão sobre o funil solicitado.

***

### Boas práticas

* Use `limit` entre 25 e 50 para alimentar interfaces. Valores altos aumentam o tempo de resposta e o risco de timeout.
* Ao reaplicar filtros, sempre reinicie `page` em `1`.
* Prefira paginar por `columnId` quando o objetivo é reproduzir o Kanban ou exportar o funil de forma previsível.
* Envie todos os campos do corpo, mesmo os desligados (`[]` ou `null`). Isso mantém o payload compatível com a interface e facilita a depuração comparando com as requisições do navegador.
* Os resultados sempre respeitam as permissões da chave de API. Duas chaves diferentes podem receber contagens diferentes para os mesmos filtros.


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://docs.sprinthub.com/topicos/api/api-listar-oportunidades-do-funil-com-filtros-e-paginacao.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
