
## List tasks

`GET /v1/tasks`

Returns a list of tasks in your Bitrix24 account with support for filtering, sorting, and auto-pagination.

## Parameters

| Parameter | Type | Default | Description |
|----------|-----|-----------|---------|
| `limit` | number | `50` | Number of records (up to 5000). When `limit > 50`, the API automatically requests multiple pages |
| `offset` | number | `0` | Skip N records. When `offset > 0`, `limit ≤ 500` is recommended |
| `select` | string | — | Field selection: `?select=id,title,status,responsibleId` |
| `order` | object | `id desc` | Sorting: `?order[id]=desc`, `?order[createdDate]=desc` |
| `filter` | object | — | Filtering by the fields from `GET /v1/tasks/fields`.<br>[Filtering syntax](/docs/filtering). Example: `?filter[status]=2&filter[responsibleId]=1` |
| `withTotal` | string | — | Whether you need the count: `true` or `false`. `false` — remove the count from the response; this is the only guaranteed way to remove `meta.total`. Above a `limit` of 50 the platform still needs the count to plan the walk, so the parameter removes the number, not the load. Without the parameter: the API key setting, then the platform default. [Paging and counts](/docs/entity-api#paging-and-record-counts) |

> **Which dates are filterable.** B24 `tasks.task.list` supports filters by `createdDate`, `changedDate`, `closedDate`, `deadline`, `dateStart`. The fields `statusChangedDate` and `activityDate` are **not filterable** on the Bitrix24 side (they are not in the method's list of filterable fields) — such a filter is silently ignored; use `changedDate` as the closest substitute. A filter on `timeSpentInLogs` is silently ignored the same way — you cannot narrow a selection by the time actually spent, and the sum over a selection comes from [aggregation](./aggregate.md). Participants and observers can each be filtered by only one user at a time: `?filter[accomplices]=25`, `?filter[auditors]=25`; tags — `?filter[tags]=tag`.

> **`status` vs `realStatus`.** `filter[status]` in Bitrix24 is a **virtual (meta) filter**: values `−1` (overdue), `−2` (unviewed), `−3` (almost overdue) — not the number from the `status` field of the response — so `filter[status]=2` will not return tasks with status `2`. To filter and sort by the actual status, use `realStatus`: `?filter[realStatus]=2` (pending), `?filter[realStatus]=5` (completed), `?sort=realStatus`. The `realStatus` value matches the `status` field in the response.

> **`meta.total` does not arrive on every call.** When `limit` is at most 50 and `offset` is zero, the count does not have to be requested: if the page came back shorter than `limit`, `meta.total` still arrives with the exact number — the collection ended on that page (an empty result gives `0`); if the page came back full, the field is absent. When `limit` is above 50 `meta.total` arrives — the count runs only where it cannot be avoided — and an explicit `withTotal=false` removes it there too. Check whether the field is present in a given response, and page by `meta.hasMore`.

## Examples

### curl — personal key

```bash
curl "https://vibecode.bitrix24.com/v1/tasks?limit=10&filter[status]=2&order[id]=desc" \
  -H "X-Api-Key: YOUR_API_KEY"
```

### curl — OAuth application

```bash
curl "https://vibecode.bitrix24.com/v1/tasks?limit=10&filter[status]=2&order[id]=desc" \
  -H "X-Api-Key: YOUR_APP_KEY" \
  -H "Authorization: Bearer USER_SESSION_TOKEN"
```

### JavaScript — personal key

```javascript
const url = 'https://vibecode.bitrix24.com/v1/tasks?limit=10&filter[status]=2&order[id]=desc'
const res = await fetch(url, {
  headers: {
    'X-Api-Key': 'YOUR_API_KEY',
  },
})

const { success, data, meta } = await res.json()
console.log(`Received ${data.length} of ${meta.total} tasks`)
```

### JavaScript — OAuth application

```javascript
const url = 'https://vibecode.bitrix24.com/v1/tasks?limit=10&filter[status]=2&order[id]=desc'
const res = await fetch(url, {
  headers: {
    'X-Api-Key': 'YOUR_APP_KEY',
    'Authorization': 'Bearer USER_SESSION_TOKEN',
  },
})

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

## Response fields

| Field | Type | Description |
|------|-----|---------|
| `success` | boolean | Always `true` on success |
| `data` | array | Array of tasks (all fields — see [Task fields](./fields.md)) |
| `meta.total` | number | Total number of records matching the filter. An optional field — see the note above |
| `meta.hasMore` | boolean | Whether there are more records beyond `limit` |

The card URL of any task from the `data` array is built from its `id` and the employee ID:

```
https://<portal>.bitrix24.com/company/personal/user/<responsibleId>/tasks/task/view/<id>/
```

`<responsibleId>` — the responsible person's ID (the `responsibleId` field of each element): the task opens in their personal workspace. The `user/<...>` segment determines whose workspace the tasks page is shown in — substitute the ID of the employee you need, for example the current one. `<portal>` — the Bitrix24 account domain. Access is limited by the employee's permissions in Bitrix24.

## Response example

```json
{
  "success": true,
  "data": [
    {
      "id": 289,
      "title": "Prepare the quarterly report",
      "status": 2,
      "priority": 1,
      "responsibleId": 79,
      "createdBy": 99,
      "createdDate": "2026-05-12T09:11:18+00:00",
      "deadline": "2026-05-19T18:00:00+00:00",
      "groupId": 0,
      "accomplices": [],
      "auditors": [],
      "tags": {},
      "notViewed": false,
      "chatId": 3567,
      "creator": {
        "id": "99",
        "name": "John Smith",
        "link": "/company/personal/user/99/"
      },
      "responsible": {
        "id": "79",
        "name": "Jane Doe",
        "link": "/company/personal/user/79/"
      }
    }
  ],
  "meta": {
    "total": 184,
    "hasMore": true
  }
}
```

## Error response example

403 — no scope:

```json
{
  "success": false,
  "error": {
    "code": "SCOPE_DENIED",
    "message": "This endpoint requires 'tasks' scope"
  }
}
```

## Errors

| HTTP | Code | Description |
|------|-----|---------|
| 403 | `SCOPE_DENIED` | The API key does not have the `tasks` scope |
| 401 | `TOKEN_MISSING` | The API key has no configured tokens |
| 401 | `MISSING_API_KEY` | The `X-Api-Key` header was not passed |
| 401 | `INVALID_API_KEY` | An invalid or non-existent key was passed |

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

## Known specifics

**When to switch to `POST /v1/tasks/search`.** If a request has many filter conditions, or you need to export records over a large date range, choose `POST /v1/tasks/search` — parameters are passed in the body, and the request can be split automatically into time windows for result sets over 5000 records. See [Search tasks](./search.md).

**Type coercion works at the top level and does not descend into objects.** The card fields (`creator`, `responsible`, `group`, `accomplicesData`, `auditorsData`) are declared as objects and arrive from Bitrix24 as-is — the values inside them stay exactly as the Bitrix24 account returned them, including `creator.id` as a string (`"99"`). That is not the same as the top-level `createdBy`, which arrives as a number. Convert via `Number()` for arithmetic on a nested identifier.

**Value types match the schema.** Fields declared as numbers in the [schema](./fields.md) (`id`, `status`, `priority`, `responsibleId`, `createdBy`, `groupId`, `chatId`, and similar) arrive as numbers; yes/no flags arrive as `true`/`false`; empty `tags`, `group`, `accomplicesData` and `auditorsData` arrive as an empty object `{}`. Converting via `Number(value)` is no longer needed. These values used to arrive as strings — if your code compares them against a string (`status === "2"`), it needs updating.

## See also

- [Get task](./get.md)
- [Search tasks](./search.md)
- [Task fields](./fields.md)
- [Aggregate tasks](./aggregate.md)
- [Filtering syntax](/docs/filtering)
- [Batch requests](/docs/batch)
- [Limits and optimization](/docs/optimization)
