For AI agents: markdown of this page — /docs-content-en/entities/workgroups/search.md documentation index — /llms.txt
Search workgroups
POST /v1/workgroups/search
Returns a list of workgroups matching the given filters. The same contract as GET /v1/workgroups, but the conditions are passed in the request body — suitable for long filters and non-Latin values.
Request fields (body)
| Field | Type | Description |
|---|---|---|
filter |
object | Filtering conditions. Field list: GET /v1/workgroups/fields. Syntax: Filtering. |
select |
array | List of fields in the response. Names — from GET /v1/workgroups/fields. |
sort |
object | Sorting: {"<field>": "ASC"|"DESC"}. |
limit |
number | Maximum records. Default 50, maximum 5000. |
offset |
number | Offset from the start of the result set. Default 0. Together with a date-range filter wider than 14 days it is rejected — see UNSTABLE_OFFSET_PAGINATION in the "Errors" section. |
autoWindow |
boolean | Split the result set into weekly windows when filtering by a date range wider than 14 days. Defaults to true. false disables splitting |
For limit > 50 Vibecode automatically paginates the request on the server side. The maximum is 5000 records per call. If more match the filter — meta.hasMore will be true.
Get projects only
A single collection stores both workgroups and projects. The isProject field distinguishes them: true — a project, false — an ordinary workgroup. To select projects, pass "filter": { "isProject": "Y" }.
Examples
curl — personal key
curl -X POST "https://vibecode.bitrix24.com/v1/workgroups/search" \
-H "X-Api-Key: YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"filter": { "%name": "Marketing", "archived": "N" },
"select": ["id", "name", "ownerId", "membersCount"],
"sort": { "dateCreate": "DESC" },
"limit": 5
}'
curl — OAuth application
curl -X POST "https://vibecode.bitrix24.com/v1/workgroups/search" \
-H "X-Api-Key: YOUR_APP_KEY" \
-H "Authorization: Bearer USER_SESSION_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"filter": { "%name": "Marketing", "archived": "N" },
"select": ["id", "name", "ownerId", "membersCount"],
"sort": { "dateCreate": "DESC" },
"limit": 5
}'
JavaScript — personal key
const res = await fetch('https://vibecode.bitrix24.com/v1/workgroups/search', {
method: 'POST',
headers: {
'X-Api-Key': 'YOUR_API_KEY',
'Content-Type': 'application/json',
},
body: JSON.stringify({
filter: { '%name': 'Marketing', archived: 'N' },
select: ['id', 'name', 'ownerId', 'membersCount'],
sort: { dateCreate: 'DESC' },
limit: 5,
}),
})
const { success, data, meta } = await res.json()
console.log(`Found ${meta.total} workgroups`)
JavaScript — OAuth application
const res = await fetch('https://vibecode.bitrix24.com/v1/workgroups/search', {
method: 'POST',
headers: {
'X-Api-Key': 'YOUR_APP_KEY',
'Authorization': 'Bearer USER_SESSION_TOKEN',
'Content-Type': 'application/json',
},
body: JSON.stringify({
filter: { '%name': 'Marketing', archived: 'N' },
select: ['id', 'name', 'ownerId', 'membersCount'],
sort: { dateCreate: 'DESC' },
limit: 5,
}),
})
const { success, data, meta } = await res.json()
Response fields
| Field | Type | Description |
|---|---|---|
success |
boolean | Always true on success |
data |
array | Array of workgroups (all fields — see Workgroup fields) |
meta.total |
number | How many records matched the filter |
meta.hasMore |
boolean | Whether there is a next page |
meta.durationMs |
number | Request duration in milliseconds |
meta.autoWindowed |
boolean | true if the result set was split into time windows |
meta.windowCount |
number | Number of windows. Present with autoWindowed: true |
meta.batchWaves |
number | Number of parallel request waves. Present with autoWindowed: true |
The meta fields sit next to data, not inside it. Pages must be walked by meta.hasMore: a data length equal to limit does not rule out the last page.
Response example
{
"success": true,
"data": [
{
"id": 85,
"name": "Marketing 2026",
"ownerId": 1271,
"membersCount": 2,
"dateCreate": "2026-03-20T06:45:10.000Z"
},
{
"id": 83,
"name": "New product development team",
"ownerId": 1269,
"membersCount": 1,
"dateCreate": "2026-03-20T06:41:07.000Z"
},
{
"id": 81,
"name": "Regional office launch",
"ownerId": 1271,
"membersCount": 1,
"dateCreate": "2026-03-20T06:29:07.000Z"
}
],
"meta": {
"total": 3,
"hasMore": false
}
}
With a date-range filter wider than 14 days, meta additionally returns autoWindowed, windowCount, and batchWaves:
{
"success": true,
"data": [ /* ... */ ],
"meta": {
"total": 29,
"hasMore": true,
"autoWindowed": true,
"windowCount": 131,
"batchWaves": 3,
"durationMs": 4217
}
}
Error response example
401 — no authorization key was passed:
{
"success": false,
"error": {
"code": "MISSING_API_KEY",
"message": "API key required. Pass via X-Api-Key header."
}
}
Errors
| HTTP | Code | Description |
|---|---|---|
| 400 | INVALID_PARAMS |
The request body does not parse or contains invalid fields |
| 401 | MISSING_API_KEY |
The X-Api-Key header was not passed |
| 401 | INVALID_API_KEY |
The provided key was not recognized |
| 403 | SCOPE_DENIED |
The key is missing the sonet_group scope |
| 400 | UNSTABLE_OFFSET_PAGINATION |
offset greater than zero together with a date-range filter wider than 14 days. Two different retrieval algorithms produce inconsistent results, so the request is rejected. Take everything in a single request with limit up to 5000, or pass autoWindow: false with sorting by id, or split the date range into parts yourself |
Full list of common API errors — Errors.
Known specifics
Time-window splitting. A date-range filter wider than 14 days is automatically split into weekly windows executed in parallel waves, so the result set bypasses the ceiling of 5000 records per call. meta then returns autoWindowed: true, the number of windows windowCount, and the number of waves batchWaves. The autoWindow: false parameter disables splitting. While splitting is active, an offset greater than zero is rejected with UNSTABLE_OFFSET_PAGINATION.
Boolean fields in the filter can be passed in two ways. In the POST body both Y / N and native JSON true / false are allowed: "filter": {"active": "Y"} and "filter": {"active": true} produce the same result set. In the response the same fields always come back as true / false.
A % prefix in the field name — substring search. "filter": {"%name": "Marketing"} will find all groups whose name contains "Marketing". Without the prefix the filter requires an exact match.
The sort parameter in the body is sort. An order key in the body is ignored without an error — the result set is returned in the default order. Use "sort": {"dateCreate": "DESC"} or the string form "sort": "dateCreate" (the default direction is ASC).