## Workgroup members

`GET /v1/workgroups/:groupId/users`

Returns the members of a workgroup together with their role in it — owner, moderator or member.

## Parameters

| Parameter | Type | Required | Default | Description |
|-----------|------|:----:|---------|-------------|
| `groupId` (path) | number | ★ yes | — | Workgroup identifier. List: [`GET /v1/workgroups`](../workgroups.md) |

The operation takes no pagination parameters: the whole roster is returned.

## Examples

### curl — personal key

```bash
curl "https://vibecode.bitrix24.com/v1/workgroups/85/users" \
  -H "X-Api-Key: YOUR_API_KEY"
```

### curl — OAuth application

```bash
curl "https://vibecode.bitrix24.com/v1/workgroups/85/users" \
  -H "X-Api-Key: YOUR_APP_KEY" \
  -H "Authorization: Bearer USER_SESSION_TOKEN"
```

### JavaScript — personal key

```javascript
const res = await fetch('https://vibecode.bitrix24.com/v1/workgroups/85/users', {
  headers: {
    'X-Api-Key': 'YOUR_API_KEY',
  },
})

const { success, data } = await res.json()
const moderators = data.filter(m => m.role === 'A' || m.role === 'E')
console.log('Owners and moderators:', moderators.length)
```

### JavaScript — OAuth application

```javascript
const res = await fetch('https://vibecode.bitrix24.com/v1/workgroups/85/users', {
  headers: {
    'X-Api-Key': 'YOUR_APP_KEY',
    'Authorization': 'Bearer USER_SESSION_TOKEN',
  },
})

const { success, data } = await res.json()
```

## Response fields

| Field | Type | Description |
|-------|------|-------------|
| `success` | boolean | Always `true` on success |
| `data[].userId` | number | User identifier. Record: [`GET /v1/users`](/docs/entities/users) |
| `data[].role` | string | Role of the user in the group: `A` owner, `E` moderator, `K` member |
| `meta.total` | number | Number of members. Always equals the length of `data` |
| `meta.warnings[]` | object | Present only in two special cases — see "Known specifics" |

## Response example

```json
{
  "success": true,
  "data": [
    { "userId": 1269, "role": "A" },
    { "userId": 1271, "role": "E" },
    { "userId": 779, "role": "K" }
  ],
  "meta": {
    "total": 3
  }
}
```

## Error response example

404 — there is no group with this `groupId`, or it is not visible to this key:

```json
{
  "success": false,
  "error": {
    "code": "ENTITY_NOT_FOUND",
    "message": "Workgroup not found, or not visible to the identity this key acts as"
  }
}
```

## Errors

| HTTP | Code | Description |
|------|------|-------------|
| 400 | `INVALID_PARAMS` | `groupId` is not a canonical positive integer |
| 401 | `MISSING_API_KEY` | `X-Api-Key` was not sent |
| 401 | `INVALID_API_KEY` | The key is not recognized — no such key exists on the platform |
| 401 | `TOKEN_MISSING` | The key carries no Bitrix24 tokens |
| 403 | `SCOPE_DENIED` | The key lacks the `sonet_group` scope |
| 404 | `ENTITY_NOT_FOUND` | The group does not exist, or is not visible to the account the key acts as |
| 502 | `BITRIX_UNAVAILABLE` | Bitrix24 returned a response or a member row this endpoint cannot parse |
| 503 | `BITRIX_TIMEOUT` | Bitrix24 accepted the call but did not answer in time. Carries a `Retry-After` header |

The full list of common API errors — [Errors](/docs/errors).

## Known specifics

- **The role arrives as the Bitrix24 letter, verbatim.** An unrecognized letter is passed through rather than mapped onto a known one or dropped, so the contract survives a role Bitrix24 may add later. Branch on the values you know and treat anything else as no permission — never default to "member".
- **The owner is not necessarily among the rows.** The owner identifier is served by the `ownerId` field of [`GET /v1/workgroups/:id`](./get.md); do not infer the owner from the presence of a row with role `A`.
- **An empty roster is an ordinary answer, not an error.** An existing group may have no members recorded at all, in which case `200` arrives with an empty `data`.
- **`404` does not mean "the group does not exist".** Bitrix24 refuses a missing group and a group invisible to this key identically, so the two cannot be told apart on the API side.
- **This is membership data, not an authorization decision.** What the endpoint shows depends on the identity behind the key: a personal key and a webhook read as their owner, while an OAuth key with a forwarded user session reads as that user. Bitrix24 account administrator status is not part of this answer — it is served by [`GET /v1/users/me`](/docs/entities/users/me). An "owner, moderator or Bitrix24 account administrator" gate is assembled from two sources.
- **A non-numeric or fractional `groupId` returns `400` rather than another group's data.** Bitrix24 truncates such an identifier and would answer with a different group's roster — the platform refuses the request before the call.
- **There is no pagination:** `limit` and `offset` are not accepted and are ignored, the whole roster is returned, and `meta.total` always equals the length of `data`.
- **`meta.warnings` appears in two cases only:** `DUPLICATE_MEMBER_ROW` — Bitrix24 returned more than one row for the same user (rows are passed through as they are; if their roles disagree, treat the membership as ambiguous), and `MEMBER_ROSTER_PAGE_BOUNDARY` — exactly 50 rows came back, which is indistinguishable from a truncated first page; cross-check the `membersCount` field of [`GET /v1/workgroups/:id`](./get.md) when the exact roster matters.
- **The operation is not available through [`POST /v1/batch`](/docs/batch)** — nested resources are not addressable there.

## See also

- [Get a workgroup](./get.md)
- [List workgroups](./list.md)
- [Workgroup fields](./fields.md)
