Chat filters in the API
Chat filters are conditions used by the API to select chats: for example, 'unread', 'with the tag Paid', or 'came from Google'. The same filter works in search, counting, exporting, and event subscrip
Chat filters are conditions used by the API to select chats: for example, 'unread', 'with the tag Paid', or 'came from Google'. The same filter works in search, counting, exporting, and event subscriptions.
This article covers how the filter is structured, all fields and operators, and ready-to-use examples you can copy.
Where chat filters work
Request | What it does |
|---|---|
POST /chats/v1/search | List of chats |
POST /chats/v1/stats | Number of chats in each status |
POST /chats/v1/export | |
POST /chats/v1/realtime |
The filter is passed in the
filter field of the request body, next to bot_id.Single-condition filter
A filter condition consists of three parts:
field, operator, and value. For example, the condition below selects chats with the status manual:Тело запросаjson
{
"bot_id": "ID_БОТА",
"filter": { "field": "status", "operator": "is", "value": "manual" }
}Read as: 'status — equals — manual'.
Multiple conditions: and and or groups
To combine filter conditions, place them in a group with
logic and filters fields. "logic": "and" — all conditions must be met, "or" — at least one must be met.Чаты у операторов с непрочитанными сообщениямиjson
{
"bot_id": "ID_БОТА",
"filter": {
"logic": "and",
"filters": [
{ "field": "status", "operator": "is", "value": "manual" },
{ "field": "incoming_unread_count", "operator": "more_number", "value": 0 }
]
}
}Groups can be nested within each other. Here are chats with a tag managed by an operator or AI:
Вложенная группаjson
{
"logic": "and",
"filters": [
{ "field": "tags", "operator": "has_any", "value": ["ID_ТЕГА"] },
{
"logic": "or",
"filters": [
{ "field": "status", "operator": "is", "value": "manual" },
{ "field": "status", "operator": "is", "value": "ai" }
]
}
]
}Single filter limitations:
- up to 64 conditions and groups;
- up to 5 nesting levels;
- up to 100 values in a single list.
Filter fields: search, status, assignee
The
field field in the filter condition is what is being checked. Search by client, chat status, who wrote last, unread messages, and assignee:Field | What it checks | Operators | Value |
|---|---|---|---|
query | Client name, username, or Telegram ID | No operator | Text up to 128 characters |
status | Chat status | is, is_any, is_not | manual, ai, waiting, ignore, blocked, error, stopped, finished, start, lead |
last_message_sender_type | Who wrote last | is, is_any, is_not | incoming — client, outcoming — your side |
incoming_unread_count | Unread client messages | Numeric | Number |
assign_id | Assignee | is, is_any, is_not, is_empty, is_not_empty | Space member ID |
What is ignore
ignore is not a separate status, but a question: the chat is in manual status, and the last message came from the client. This means the client must be answered.Filter fields: tags, custom fields, Tracker
Tags and custom fields are filtered only by id, not by name. For
custom_fields and tracker_fields, you also need a key in the condition:Field | What it checks | Operators | Value |
|---|---|---|---|
tags | Chat tags | has_any, has_all, has_only, has_none, is_not_empty | List of tag ids |
custom_fields | Field value | is, is_not, is_any | Plus key — field id |
tracker_fields | Tracker label, for example utm_source | is, is_not, is_any | Plus key — label name |
tracker_events | Tracker events, for example purchase | has_any, has_all, has_none, is_not_empty | For example, ["purchase"] |
Filter fields: dates, amount, scenario, id
Dates in the filter —
created_at and updated_at, lead amount — cost, position in the scenario — step and sales stage:Field | What it checks | Operators | Value |
|---|---|---|---|
created_at | When the chat was created | before, after, between | Date |
updated_at | Time of the last message | before, after, between | Date |
cost | Amount associated with the lead | Numeric | Number |
current_flow_id, current_step_id | Current scenario and step | is, is_any, is_not, is_empty, is_not_empty | id |
current_sale_stage_id | Sales stage | is, is_any, is_not, is_not_empty | id |
id, external_id | chat id or Telegram client id | is, is_any, is_not | id |
Filter operators
Operator | Value | Meaning |
|---|---|---|
is / is_not | Single value | Equal to / Not equal to |
is_any | List | Equal to any from the list |
is_empty / is_not_empty | No value | Field is empty / filled |
has_any | List | Contains at least one of the values |
has_all | List | Contains all values, and possibly others |
has_only | List | Exactly these values, and no others. |
has_none | List | None of the values |
before / after | Date | Strictly earlier / strictly later |
between | Two dates | In the range, inclusive of boundaries |
more_number, less_number, more_equal_number, less_equal_number, equal_number, not_equal_number | Number | Greater than, less than, greater than or equal to, less than or equal to, equal to, not equal to |
Dates in filters and time zones
You can write the date in full —
2026-10-01T00:00:00Z — or just as a day: 2026-10-01. To have the day calculated according to your time rather than UTC, add timezone:Чаты, появившиеся в октябре по Москвеjson
{ "field": "created_at", "operator": "between", "value": ["2026-10-01", "2026-10-31"], "timezone": "Europe/Moscow" }Filter examples: who has not been answered
Client not answered
Status
ignore: chat is in manual mode, and the last message was sent by the client.Фильтрjson
{ "field": "status", "operator": "is", "value": "ignore" }Unanswered, and chat is unassigned
Status
ignore and empty assignee: assign_id with operator is_empty.Фильтрjson
{
"logic": "and",
"filters": [
{ "field": "status", "operator": "is", "value": "ignore" },
{ "field": "assign_id", "operator": "is_empty" }
]
}Filter examples: purchases, fields, dates
Purchased, came from Google
Tracker label
utm_source is equal to google, and the lead has a purchase event in tracker_events.Фильтрjson
{
"logic": "and",
"filters": [
{ "field": "tracker_fields", "key": "utm_source", "operator": "is", "value": "google" },
{ "field": "tracker_events", "operator": "has_any", "value": ["purchase"] }
]
}City from field — Moscow
Custom field 'City' is equal to 'Moscow'. In
key — field ID from GET /bots/v1/{bot_id}/custom-fields.Фильтрjson
{ "field": "custom_fields", "key": "ID_ПОЛЯ_ГОРОД", "operator": "is", "value": "Москва" }Correspondence for the last 24 hours
Last message after the specified time:
updated_at with the after operator.Фильтрjson
{ "field": "updated_at", "operator": "after", "value": "2026-10-29T12:00:00Z" }How many chats are in each status
The number of chats by status is returned by
POST /chats/v1/stats. Pass the same filter as in the search, or a request without a filter—the total number total and the counters statuses will be returned:Запросbash
curl -X POST 'https://api.chatterfy.ai/public-api/chats/v1/stats' \
-H 'ApiKey: ВАШ_КЛЮЧ' \
-H 'Content-Type: application/json' \
-d '{"bot_id": "ID_БОТА"}'Ответjson
{
"total": 3634,
"statuses": [
{ "status": "waiting", "count": 2980 },
{ "status": "manual", "count": 605 },
{ "status": "ai", "count": 33 },
{ "status": "blocked", "count": 16 },
{ "status": "ignore", "count": 421 }
]
}ignore chats are part of manual chats, so they are not counted twice in total.Frequently Asked Questions
Related
Was this article helpful?

