> 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/en/topics/api/api-list-funnel-opportunities-with-custom-field-filter.md).

# API - List Funnel Opportunities with Custom Field Filter

### API - List Opportunities in Pipeline with Custom Field Filter

#### List opportunities in a pipeline

`POST` `/crm/opportunities/XXXX?i=instancia&apitoken=XXXXXXX`

XXXX = Pipeline ID (CRM)

Full endpoint: `https://sprinthub-api-master.sprinthub.app/crm/opportunities/XXXX?i=instancia&apitoken=XXXXXXX`

Unlike other CRM endpoints, authentication here goes in the **query string**, not in headers.

**Headers**

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

**Body**

| Field                       | Type         | Required | Description                                                            |
| --------------------------- | ------------ | -------- | ---------------------------------------------------------------------- |
| `page`                      | number       | **Yes**  | Page, starts at 0. It only actually paginates when there is `columnId` |
| `limit`                     | number       | **Yes**  | Maximum **100**. Above that returns 400                                |
| `filters`                   | array        | No       | Conditions on custom fields. See below                                 |
| `columnId`                  | number       | No       | Stage ID. **Changes the response format**                              |
| `filterByUsers`             | array        | No       | Responsible user IDs. Empty = all                                      |
| `filterByStatus`            | array        | No       | Included statuses: `open`, `gain`, `lost`                              |
| `filterByCreateDate`        | date \| null | No       | Creation date window                                                   |
| `filterByExpectedCloseDate` | date \| null | No       | Expected closing date window                                           |
| `search`                    | string       | No       | Searched text. Does not reach custom fields                            |
| `searchBy`                  | string       | No       | Where to search. Accepts **only** `lead` or `opportunity`              |

```
{
    "filterByUsers": [],
    "filterByStatus": ["open", "gain", "lost"],
    "filterByCreateDate": null,
    "filterByExpectedCloseDate": null,
    "filters": [],
    "search": "",
    "searchBy": "lead",
    "columnId": 19,
    "page": 0,
    "limit": 100
}
```

#### Filter by custom field

Each condition in the array `filters` has two layers: the outer one identifies the condition type, and `properties` carries the comparison.

| Field                  | Type   | Required | Description                                                                         |
| ---------------------- | ------ | -------- | ----------------------------------------------------------------------------------- |
| `filterType`           | string | **Yes**  | `opField` for opportunity field. **Without it the condition is silently discarded** |
| `properties.field`     | string | **Yes**  | Field name, exactly as in the CRM. It is not an ID                                  |
| `properties.value`     | string | **Yes**  | Searched value                                                                      |
| `properties.operator`  | string | No       | `=`, `!=` or `contains`. Omitted, assumes `=`                                       |
| `properties.fieldType` | string | No       | Field type, e.g. `text`                                                             |
| `category`             | string | No       | `opportunity` for opportunity field                                                 |
| `operator`             | string | No       | Combination with others: `AND` or `OR`                                              |
| `id`                   | string | No       | Used by the panel to identify the row in the interface. The API ignores             |

```
{
    "filters": [
        {
            "operator": "AND",
            "category": "opportunity",
            "filterType": "opField",
            "properties": {
                "field": "ID Omie",
                "fieldType": "text",
                "operator": "=",
                "value": "123456"
            }
        }
    ]
}
```

**Operators:** `=` compares the exact value, `!=` brings everything that is not that value, `contains` searches for a segment — `845` finds `84521`. The values `like` e `isNotNull` are accepted by the API but do not filter.

Multiple conditions in the array are applied together. Even though several fields are optional, the recommended approach is to send the complete structure, as the panel sends it.

#### Response

**200 — without `columnId` (kanban)**

Stage array, each one with `total`, `totalValue` e `items`. In this mode `page` is ignored and `items` brings only the first `limit` opportunities from each stage.

```
[
    {
        "id": 19,
        "name": "Proposta",
        "sequence": 0,
        "crm": 5,
        "total": 1,
        "totalValue": "22.10",
        "items": [
            {
                "id": 4079,
                "title": "Unique No.: 47004",
                "value": "22.10",
                "crm_column": 19,
                "crm_id": 5,
                "lead_id": 75358,
                "sequence": 4,
                "status": "open",
                "user": 191,
                "fields": {
                    "ID Omie": "123456",
                    "Item 1": "item1here",
                    "Invoice": "",
                    "Carrier": ""
                },
                "dataLead": { }
            }
        ]
    },
    {
        "id": 20,
        "name": "Follow Up",
        "total": 0,
        "totalValue": 0,
        "items": []
    }
]
```

**200 — with `columnId` (flat list)**

Direct list of the stage's opportunities, with pagination working.

```
[
    {
        "id": 4079,
        "title": "Unique No.: 47004",
        "value": "22.10",
        "crm_column": 19,
        "crm_id": 5,
        "lead_id": 75358,
        "sequence": 4,
        "status": "open",
        "fields": {
            "ID Omie": "123456"
        }
    }
]
```

**400 — `page` or `limit` missing**

```
{
    "msg": "must have required property 'page'",
    "details": {
        "instancePath": "",
        "schemaPath": "#/required",
        "keyword": "required",
        "params": { "missingProperty": "page" }
    }
}
```

**400 — `limit` above 100**

```
{
    "msg": "must be <= 100",
    "details": {
        "instancePath": "/limit",
        "schemaPath": "#/properties/limit/maximum",
        "keyword": "maximum",
        "params": { "limit": 100 }
    }
}
```

**400 — `searchBy` invalid**

```
{
    "msg": "must be equal to one of the allowed values",
    "details": {
        "instancePath": "/searchBy",
        "params": { "allowedValues": ["lead", "opportunity"] }
    }
}
```

#### Notes

**Custom fields are defined by pipeline.** A field that exists in one pipeline may not exist in another. Filtering by a field that does not exist in that pipeline returns an empty list with status **200 OK**, with no error message.

**The array `filters` has no schema for the items.** The API only validates that it is an array. A condition without `filterType` — or malformed in another way — is silently discarded, and the response returns **complete** with status 200, giving the impression that the filter was applied.

To confirm that the filter is active, make the same call with an `value` nonexistent. Empty result means filter working; complete result means filter ignored.

**The pipeline and stage IDs come from** `GET /crm?i=instancia&apitoken=XXXXXXX`, which returns the pipelines with the stages embedded in the field `columns`.


---

# 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/en/topics/api/api-list-funnel-opportunities-with-custom-field-filter.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.
