[{"data":1,"prerenderedAt":14},["ShallowReactive",2],{"docs-entities\u002Ftasks\u002Ftime":3,"docs-tabs-entities\u002Ftasks\u002Ftime":6},{"content":4,"lastmod":5},"# Task time tracking\n\nTime-tracking entries are a nested resource of a task. Each entry has a duration, an author, a comment, and a creation time. The base path is `\u002Fv1\u002Ftasks\u002F:taskId\u002Ftime`. These operations require an existing task `:taskId` in the Bitrix24 account. Entries from every task at once are served by a separate path, `\u002Fv1\u002Ftask-time`.\n\nBitrix24 API: `task.elapseditem.*`\nScope: `task`\n\n## Operations\n\n- [Add an entry](.\u002Ftime\u002Fcreate.md) — `POST \u002Fv1\u002Ftasks\u002F:taskId\u002Ftime`\n- [List time-tracking entries](.\u002Ftime\u002Flist.md) — `GET \u002Fv1\u002Ftasks\u002F:taskId\u002Ftime`\n- [Get a time-tracking entry](.\u002Ftime\u002Fget.md) — `GET \u002Fv1\u002Ftasks\u002F:taskId\u002Ftime\u002F:itemId`\n- [Update a time-tracking entry](.\u002Ftime\u002Fupdate.md) — `PATCH \u002Fv1\u002Ftasks\u002F:taskId\u002Ftime\u002F:itemId`\n- [Delete a time-tracking entry](.\u002Ftime\u002Fdelete.md) — `DELETE \u002Fv1\u002Ftasks\u002F:taskId\u002Ftime\u002F:itemId`\n- [List entries across the whole Bitrix24 account](.\u002Ftime\u002Fglobal-list.md) — `GET \u002Fv1\u002Ftask-time`\n- [Entry fields](.\u002Ftime\u002Ffields.md) — `GET \u002Fv1\u002Ftask-time\u002Ffields`\n\n## Key fields\n\nThe same fields are served by the machine-readable schema [`GET \u002Fv1\u002Ftask-time\u002Ffields`](.\u002Ftime\u002Ffields.md) — type, read-only flag, label and description for each.\n\n| Field | Type | Description |\n|------|-----|---------|\n| `id` | number | Entry identifier |\n| `taskId` | number | Parent task ID |\n| `userId` | number | Author. Employee list: `GET \u002Fv1\u002Fusers` |\n| `seconds` | number | Duration in seconds. The primary field, set at creation |\n| `minutes` | number | Duration in minutes, derived from `seconds`, filled by the system |\n| `commentText` | string | Comment for the entry. An empty comment is returned as `\"\"`, not `null` |\n| `source` | string | Source: `2` — the entry was created through the REST API |\n| `createdDate` | datetime | Entry creation date |\n| `dateStart`, `dateStop` | datetime | Start and end of the tracked interval. Filled automatically and not editable through the current API |\n\n## What to know before you start\n\n1. **Response fields are in camelCase.** Time-tracking entries are returned in camelCase — `id`, `taskId`, `userId`, `seconds`, `minutes`, `commentText`, `source`, `createdDate`, `dateStart`, `dateStop` — like task comments and the rest of the API.\n2. **Numeric values are returned as numbers, `source` as a string.** `id`, `taskId`, `userId`, `seconds`, and `minutes` are serialized as numbers — for example `\"seconds\": 900`. This holds across every response — in list responses and in a single entry alike — so you do not need to convert them with `Number(value)`. The `source` field stays a string: `\"source\": \"2\"`.\n3. **`seconds` is the only unit of measurement on write.** The `seconds` parameter is required. The system recalculates `minutes` itself.\n4. **Entries are deleted together with the task.** If the parent task is deleted ([`DELETE \u002Fv1\u002Ftasks\u002F:id`](.\u002Fdelete.md)), its time-tracking entries become inaccessible — a separate `DELETE` for each is not required. Requesting them by their previous ID returns `404`.\n5. **`dateStart` and `dateStop` are not editable through the API.** Their values are filled by Bitrix24 automatically at the moment the entry is created. To record a specific interval, pass the total time via `seconds` in `POST` or `PATCH`. Bitrix24 consistently sets the interval about an hour ahead of `createdDate` — that is its own auto-fill, and the Vibecode API does not change the dates.\n6. **The list may show entries you cannot fetch individually.** The lists — both the global one and the one for a single task — sometimes return entries belonging to others. Requesting such an entry by its `itemId` returns `404 NOT_FOUND`. This is an access-rights mismatch on the Bitrix24 side.\n7. **The field schema lives on the flat path.** The field set is served by `GET \u002Fv1\u002Ftask-time\u002Ffields`. The nested `GET \u002Fv1\u002Ftasks\u002F:taskId\u002Ftime\u002Ffields` returns `400 WRONG_PATH` and names the correct path in the error text: the schema is the same for every task, so it is not repeated under each `:taskId`. The request needs the `task` scope and makes no Bitrix24 call.\n8. **`userId` is set on creation only.** `POST` accepts it, `PATCH` returns `400 READONLY_FIELD` — Bitrix24 cannot move an entry to another employee. The field schema marks it `createOnly`.\n9. **The comment is named differently in the response and in the request body.** It is returned as `commentText` and passed as `comment` on write.\n\n## Typical scenario\n\n1. Find or create a task: [`GET \u002Fv1\u002Ftasks`](.\u002Flist.md) \u002F [`POST \u002Fv1\u002Ftasks`](.\u002Fcreate.md).\n2. Add an entry: [`POST \u002Fv1\u002Ftasks\u002F:taskId\u002Ftime`](.\u002Ftime\u002Fcreate.md) with `seconds` and, if needed, `comment` and `userId`.\n3. View the tracking history: [`GET \u002Fv1\u002Ftasks\u002F:taskId\u002Ftime`](.\u002Ftime\u002Flist.md).\n4. Adjust the duration or comment: [`PATCH \u002Fv1\u002Ftasks\u002F:taskId\u002Ftime\u002F:itemId`](.\u002Ftime\u002Fupdate.md).\n5. Delete an erroneous entry: [`DELETE \u002Fv1\u002Ftasks\u002F:taskId\u002Ftime\u002F:itemId`](.\u002Ftime\u002Fdelete.md).\n6. Build a report for one employee over a period without iterating over tasks: [`GET \u002Fv1\u002Ftask-time`](.\u002Ftime\u002Fglobal-list.md).\n\n## Limits\n\n| Limit | Value |\n|-------|----------|\n| Entries per page | 1..500, 50 by default |\n| Request rate | shared across the Vibecode API — see [Limits and optimization](\u002Fdocs\u002Foptimization) |\n\n## See also\n\n- [Tasks](..\u002Ftasks.md)\n- [Task comments](..\u002Ftask-comments.md)\n- [Employees](\u002Fdocs\u002Fentities\u002Fusers)\n- [Limits and optimization](\u002Fdocs\u002Foptimization)\n","2026-10-09",{"time\u002Fcreate.md":7,"time\u002Flist.md":8,"time\u002Fget.md":9,"time\u002Fupdate.md":10,"time\u002Fdelete.md":11,"time\u002Fglobal-list.md":12,"time\u002Ffields.md":13},"\n## Add a time-tracking entry\n\n`POST \u002Fv1\u002Ftasks\u002F:taskId\u002Ftime`\n\nCreates a new time-tracking entry for a task — records the seconds spent and, optionally, the author of the entry and a comment on it.\n\n## Parameters\n\n| Parameter | Type | Required | Description |\n|----------|-----|:-----:|---------|\n| `taskId` (path) | number | yes | Task ID |\n\n## Request fields (body)\n\n| Field | Type | Required | Description |\n|------|-----|:-----:|---------|\n| `seconds` | number | yes | Duration in seconds |\n| `comment` | string | no | Comment for the entry. When the entry is read back, it is returned in the `commentText` field |\n| `userId` | number | no | Author ID. Defaults to the API-key user. Pass only existing employee IDs from [`GET \u002Fv1\u002Fusers`](\u002Fdocs\u002Fentities\u002Fusers) — see \"Known specifics\" |\n| `createdDate` | string | no | Date and time of the entry. Three formats are accepted: ISO 8601 with offset `2026-07-13T14:30:00+00:00`, ISO 8601 without offset `2026-07-13T14:30:00`, and a date `2026-07-13`. If the field is omitted, the entry is dated at the time it is created |\n\n## Examples\n\n### curl — personal key\n\n```bash\ncurl -X POST \"https:\u002F\u002Fvibecode.bitrix24.com\u002Fv1\u002Ftasks\u002F289\u002Ftime\" \\\n  -H \"X-Api-Key: YOUR_API_KEY\" \\\n  -H \"Content-Type: application\u002Fjson\" \\\n  -d '{\n    \"seconds\": 1800,\n    \"comment\": \"Draft preparation\"\n  }'\n```\n\n### curl — OAuth application\n\n```bash\ncurl -X POST \"https:\u002F\u002Fvibecode.bitrix24.com\u002Fv1\u002Ftasks\u002F289\u002Ftime\" \\\n  -H \"X-Api-Key: YOUR_APP_KEY\" \\\n  -H \"Authorization: Bearer USER_SESSION_TOKEN\" \\\n  -H \"Content-Type: application\u002Fjson\" \\\n  -d '{\n    \"seconds\": 1800,\n    \"comment\": \"Draft preparation\"\n  }'\n```\n\n### JavaScript — personal key\n\n```javascript\nconst res = await fetch('https:\u002F\u002Fvibecode.bitrix24.com\u002Fv1\u002Ftasks\u002F289\u002Ftime', {\n  method: 'POST',\n  headers: {\n    'X-Api-Key': 'YOUR_API_KEY',\n    'Content-Type': 'application\u002Fjson',\n  },\n  body: JSON.stringify({\n    seconds: 1800,\n    comment: 'Draft preparation',\n  }),\n})\n\nconst { success, data } = await res.json()\nconsole.log('New entry ID:', data.id)\n```\n\n### JavaScript — OAuth application\n\n```javascript\nconst res = await fetch('https:\u002F\u002Fvibecode.bitrix24.com\u002Fv1\u002Ftasks\u002F289\u002Ftime', {\n  method: 'POST',\n  headers: {\n    'X-Api-Key': 'YOUR_APP_KEY',\n    'Authorization': 'Bearer USER_SESSION_TOKEN',\n    'Content-Type': 'application\u002Fjson',\n  },\n  body: JSON.stringify({\n    seconds: 1800,\n    comment: 'Draft preparation',\n  }),\n})\n\nconst { success, data } = await res.json()\n```\n\n## Response fields\n\n| Field | Type | Description |\n|------|-----|---------|\n| `success` | boolean | Always `true` on success |\n| `data.id` | number | ID of the created entry. Use it for `GET` \u002F `PATCH` \u002F `DELETE` |\n\n## Response example\n\nHTTP 201 Created:\n\n```json\n{\n  \"success\": true,\n  \"data\": {\n    \"id\": 161\n  }\n}\n```\n\n## Error response example\n\n400 — the required `seconds` field was not provided:\n\n```json\n{\n  \"success\": false,\n  \"error\": {\n    \"code\": \"MISSING_PARAMS\",\n    \"message\": \"Required: seconds (number)\"\n  }\n}\n```\n\n## Errors\n\n| HTTP | Code | Description |\n|------|-----|---------|\n| 400 | `MISSING_PARAMS` | The `seconds` field was not provided |\n| 422 | `BITRIX_ERROR` | Bitrix24 returned an error (e.g. the parent task is inaccessible) |\n| 403 | `SCOPE_DENIED` | The API key lacks the `task` scope |\n| 401 | `TOKEN_MISSING` | The API key has no configured tokens |\n\nFull list of common API errors — [Errors](\u002Fdocs\u002Ferrors).\n\n## Known specifics\n\n**The existence of `userId` is not validated.** The entry is saved with any `userId`, even a non-existent one, and the call returns `201`. But such a \"ghost\" entry cannot then be read, updated, or deleted — `GET`, `PATCH` and `DELETE \u002Fv1\u002Ftasks\u002F:taskId\u002Ftime\u002F:itemId` return `404 NOT_FOUND`. It remains visible only in the `GET \u002Fv1\u002Ftasks\u002F:taskId\u002Ftime` and `GET \u002Fv1\u002Ftask-time` lists, cluttering reports with no way to clean it up via the API. Pass only real employee IDs from [`GET \u002Fv1\u002Fusers`](\u002Fdocs\u002Fentities\u002Fusers).\n\n**The response contains only `id`, without the other fields.** Unlike creating a task or comment, this method returns only the identifier. To get the full entry with `minutes`, `source`, `createdDate`, `dateStart` and `dateStop` filled in by the system, call [`GET \u002Fv1\u002Ftasks\u002F:taskId\u002Ftime\u002F:itemId`](.\u002Fget.md).\n\n## See also\n\n- [Get a time-tracking entry](.\u002Fget.md)\n- [List time-tracking entries](.\u002Flist.md)\n- [Update a time-tracking entry](.\u002Fupdate.md)\n- [Delete a time-tracking entry](.\u002Fdelete.md)\n- [Tasks](\u002Fdocs\u002Fentities\u002Ftasks)\n","\n## List time-tracking entries\n\n`GET \u002Fv1\u002Ftasks\u002F:taskId\u002Ftime`\n\nReturns all time-tracking entries of a specific task, sorted by `id` (newest first).\n\n## Parameters\n\n| Parameter | Type | Required | Default | Description |\n|----------|-----|:-----:|-----------|---------|\n| `taskId` (path) | number | yes | — | Task ID |\n| `limit` (query) | number | | `50` | Page size |\n| `offset` (query) | number | | `0` | Skip N entries |\n\n**Filter format.** The task is provided by the `taskId` path parameter. The generic `filter` envelope is not supported: any bracket key `filter[...]`, a non-empty `filter` value, a JSON form including `filter={}`, or a repeated `filter` parameter returns `400 UNSUPPORTED_FILTER`. A single empty `filter=` parameter means no filter and still returns `200`. To filter by employee or period, use [GET \u002Fv1\u002Ftask-time](.\u002Fglobal-list.md) with the named parameters `userId`, `taskId`, `from`, and `to`.\n\n## Examples\n\n### curl — personal key\n\n```bash\ncurl \"https:\u002F\u002Fvibecode.bitrix24.com\u002Fv1\u002Ftasks\u002F289\u002Ftime\" \\\n  -H \"X-Api-Key: YOUR_API_KEY\"\n```\n\n### curl — OAuth application\n\n```bash\ncurl \"https:\u002F\u002Fvibecode.bitrix24.com\u002Fv1\u002Ftasks\u002F289\u002Ftime\" \\\n  -H \"X-Api-Key: YOUR_APP_KEY\" \\\n  -H \"Authorization: Bearer USER_SESSION_TOKEN\"\n```\n\n### JavaScript — personal key\n\n```javascript\nconst res = await fetch('https:\u002F\u002Fvibecode.bitrix24.com\u002Fv1\u002Ftasks\u002F289\u002Ftime', {\n  headers: {\n    'X-Api-Key': 'YOUR_API_KEY',\n  },\n})\n\nconst { success, data, meta } = await res.json()\nconst totalSeconds = data.reduce((sum, r) => sum + r.seconds, 0)\nconsole.log(`Total for the task: ${totalSeconds \u002F 60} min`)\n```\n\n### JavaScript — OAuth application\n\n```javascript\nconst res = await fetch('https:\u002F\u002Fvibecode.bitrix24.com\u002Fv1\u002Ftasks\u002F289\u002Ftime', {\n  headers: {\n    'X-Api-Key': 'YOUR_APP_KEY',\n    'Authorization': 'Bearer USER_SESSION_TOKEN',\n  },\n})\n\nconst { success, data, meta } = await res.json()\n```\n\n## Response fields\n\n| Field | Type | Description |\n|------|-----|---------|\n| `success` | boolean | Always `true` on success |\n| `data` | array | Array of time-tracking entries |\n| `data[].id` | number | Entry identifier |\n| `data[].taskId` | number | Parent task ID |\n| `data[].userId` | number | Author. Profile: `GET \u002Fv1\u002Fusers\u002F:userId` |\n| `data[].seconds` | number | Duration in seconds |\n| `data[].minutes` | number | Duration in minutes (derived from `seconds`) |\n| `data[].commentText` | string | Comment for the entry |\n| `data[].source` | string | Source: `2` — REST API |\n| `data[].createdDate` | datetime | When the entry was created |\n| `data[].dateStart` | datetime | Start of the tracked interval (filled automatically) |\n| `data[].dateStop` | datetime | End of the tracked interval (filled automatically) |\n| `meta.total` | number | Total number of time-tracking entries for the task |\n\n## Response example\n\n```json\n{\n  \"success\": true,\n  \"data\": [\n    {\n      \"id\": 163,\n      \"taskId\": 289,\n      \"userId\": 1,\n      \"commentText\": \"Draft preparation\",\n      \"seconds\": 1800,\n      \"minutes\": 30,\n      \"source\": \"2\",\n      \"createdDate\": \"2026-05-13T16:15:43+00:00\",\n      \"dateStart\": \"2026-05-13T17:15:43+00:00\",\n      \"dateStop\": \"2026-05-13T17:15:43+00:00\"\n    },\n    {\n      \"id\": 161,\n      \"taskId\": 289,\n      \"userId\": 1,\n      \"commentText\": \"\",\n      \"seconds\": 600,\n      \"minutes\": 10,\n      \"source\": \"2\",\n      \"createdDate\": \"2026-05-13T16:15:41+00:00\",\n      \"dateStart\": \"2026-05-13T17:15:41+00:00\",\n      \"dateStop\": \"2026-05-13T17:15:41+00:00\"\n    }\n  ],\n  \"meta\": {\n    \"total\": 2\n  }\n}\n```\n\n## Error response example\n\n403 — no scope:\n\n```json\n{\n  \"success\": false,\n  \"error\": {\n    \"code\": \"SCOPE_DENIED\",\n    \"message\": \"This endpoint requires 'task' scope\"\n  }\n}\n```\n\n## Errors\n\n| HTTP | Code | Description |\n|------|-----|---------|\n| 400 | `UNSUPPORTED_FILTER` | An unsupported `filter` was provided; the task comes from the path, while employee and period filters are available on `GET \u002Fv1\u002Ftask-time` |\n| 403 | `SCOPE_DENIED` | The API key lacks the `task` scope |\n| 401 | `TOKEN_MISSING` | The API key has no configured tokens |\n| 404 | `TASK_NOT_FOUND` | There is no task with this `taskId`, or it is not visible to this key |\n| 422 | `BITRIX_ERROR` | Bitrix24 returned an error while reading |\n\nFull list of common API errors — [Errors](\u002Fdocs\u002Ferrors).\n\n## Known specifics\n\n**Descending sort by `id`.** The most recently added entries are returned first. `limit` and `offset` work on top of this sort.\n\n## See also\n\n- [Get a time-tracking entry](.\u002Fget.md)\n- [Add an entry](.\u002Fcreate.md)\n- [Update a time-tracking entry](.\u002Fupdate.md)\n- [Delete a time-tracking entry](.\u002Fdelete.md)\n- [Tasks](\u002Fdocs\u002Fentities\u002Ftasks)\n","\n## Get a time-tracking entry\n\n`GET \u002Fv1\u002Ftasks\u002F:taskId\u002Ftime\u002F:itemId`\n\nReturns a single time-tracking entry by its identifier.\n\n## Parameters\n\n| Parameter | Type | Required | Description |\n|----------|-----|:-----:|---------|\n| `taskId` (path) | number | yes | Task ID |\n| `itemId` (path) | number | yes | Time-tracking entry ID (from [`GET \u002Fv1\u002Ftasks\u002F:taskId\u002Ftime`](.\u002Flist.md) or the response of [`POST \u002Fv1\u002Ftasks\u002F:taskId\u002Ftime`](.\u002Fcreate.md)) |\n\n## Examples\n\n### curl — personal key\n\n```bash\ncurl \"https:\u002F\u002Fvibecode.bitrix24.com\u002Fv1\u002Ftasks\u002F289\u002Ftime\u002F161\" \\\n  -H \"X-Api-Key: YOUR_API_KEY\"\n```\n\n### curl — OAuth application\n\n```bash\ncurl \"https:\u002F\u002Fvibecode.bitrix24.com\u002Fv1\u002Ftasks\u002F289\u002Ftime\u002F161\" \\\n  -H \"X-Api-Key: YOUR_APP_KEY\" \\\n  -H \"Authorization: Bearer USER_SESSION_TOKEN\"\n```\n\n### JavaScript — personal key\n\n```javascript\nconst res = await fetch('https:\u002F\u002Fvibecode.bitrix24.com\u002Fv1\u002Ftasks\u002F289\u002Ftime\u002F161', {\n  headers: {\n    'X-Api-Key': 'YOUR_API_KEY',\n  },\n})\n\nconst { success, data } = await res.json()\nconsole.log(`Minutes spent: ${data.minutes}`)\n```\n\n### JavaScript — OAuth application\n\n```javascript\nconst res = await fetch('https:\u002F\u002Fvibecode.bitrix24.com\u002Fv1\u002Ftasks\u002F289\u002Ftime\u002F161', {\n  headers: {\n    'X-Api-Key': 'YOUR_APP_KEY',\n    'Authorization': 'Bearer USER_SESSION_TOKEN',\n  },\n})\n\nconst { success, data } = await res.json()\n```\n\n## Response fields\n\n| Field | Type | Description |\n|------|-----|---------|\n| `success` | boolean | Always `true` on success |\n| `data.id` | number | Entry identifier |\n| `data.taskId` | number | Parent task ID |\n| `data.userId` | number | Author. Profile: `GET \u002Fv1\u002Fusers\u002F:userId` |\n| `data.seconds` | number | Duration in seconds |\n| `data.minutes` | number | Duration in minutes (derived from `seconds`) |\n| `data.commentText` | string | Comment for the entry |\n| `data.source` | string | Source: `2` — REST API |\n| `data.createdDate` | datetime | When the entry was created |\n| `data.dateStart` | datetime | Start of the tracked interval |\n| `data.dateStop` | datetime | End of the tracked interval |\n\n## Response example\n\n```json\n{\n  \"success\": true,\n  \"data\": {\n    \"id\": 161,\n    \"taskId\": 289,\n    \"userId\": 1,\n    \"commentText\": \"Draft preparation\",\n    \"seconds\": 900,\n    \"minutes\": 15,\n    \"source\": \"2\",\n    \"createdDate\": \"2026-05-13T16:15:41+00:00\",\n    \"dateStart\": \"2026-05-13T17:15:41+00:00\",\n    \"dateStop\": \"2026-05-13T17:15:41+00:00\"\n  }\n}\n```\n\n## Error response example\n\n404 — the entry was not found or is inaccessible:\n\n```json\n{\n  \"success\": false,\n  \"error\": {\n    \"code\": \"NOT_FOUND\",\n    \"message\": \"Time entry not found\"\n  }\n}\n```\n\n## Errors\n\n| HTTP | Code | Description |\n|------|-----|---------|\n| 404 | `NOT_FOUND` | An entry with this `itemId` was not found or the parent task is inaccessible |\n| 403 | `SCOPE_DENIED` | The API key lacks the `task` scope |\n| 401 | `TOKEN_MISSING` | The API key has no configured tokens |\n\nFull list of common API errors — [Errors](\u002Fdocs\u002Ferrors).\n\n## See also\n\n- [List time-tracking entries](.\u002Flist.md)\n- [Update a time-tracking entry](.\u002Fupdate.md)\n- [Delete a time-tracking entry](.\u002Fdelete.md)\n- [Tasks](\u002Fdocs\u002Fentities\u002Ftasks)\n","\n## Update a time-tracking entry\n\n`PATCH \u002Fv1\u002Ftasks\u002F:taskId\u002Ftime\u002F:itemId`\n\nModifies an existing time-tracking entry. Pass only the fields you want to change.\n\n## Parameters\n\n| Parameter | Type | Required | Description |\n|----------|-----|:-----:|---------|\n| `taskId` (path) | number | yes | Task ID. List: [`GET \u002Fv1\u002Ftasks`](\u002Fdocs\u002Fentities\u002Ftasks\u002Flist) |\n| `itemId` (path) | number | yes | Time-tracking entry ID. List: [`GET \u002Fv1\u002Ftasks\u002F:taskId\u002Ftime`](\u002Fdocs\u002Fentities\u002Ftasks\u002Ftime\u002Flist) |\n\n## Request fields (body)\n\n| Field | Type | Required | Description |\n|------|-----|:-----:|---------|\n| `seconds` | number | no | New duration in seconds. After the update, `minutes` is recalculated automatically |\n| `comment` | string | no | New comment for the entry |\n| `createdDate` | string | no | New date and time of the entry. Three formats are accepted: ISO 8601 with offset `2026-07-13T14:30:00+00:00`, ISO 8601 without offset `2026-07-13T14:30:00`, and a date `2026-07-13` |\n\n## Examples\n\n### curl — personal key\n\n```bash\ncurl -X PATCH \"https:\u002F\u002Fvibecode.bitrix24.com\u002Fv1\u002Ftasks\u002F289\u002Ftime\u002F161\" \\\n  -H \"X-Api-Key: YOUR_API_KEY\" \\\n  -H \"Content-Type: application\u002Fjson\" \\\n  -d '{\n    \"seconds\": 900,\n    \"comment\": \"Refined estimate\"\n  }'\n```\n\n### curl — OAuth application\n\n```bash\ncurl -X PATCH \"https:\u002F\u002Fvibecode.bitrix24.com\u002Fv1\u002Ftasks\u002F289\u002Ftime\u002F161\" \\\n  -H \"X-Api-Key: YOUR_APP_KEY\" \\\n  -H \"Authorization: Bearer USER_SESSION_TOKEN\" \\\n  -H \"Content-Type: application\u002Fjson\" \\\n  -d '{\n    \"seconds\": 900,\n    \"comment\": \"Refined estimate\"\n  }'\n```\n\n### JavaScript — personal key\n\n```javascript\nconst res = await fetch('https:\u002F\u002Fvibecode.bitrix24.com\u002Fv1\u002Ftasks\u002F289\u002Ftime\u002F161', {\n  method: 'PATCH',\n  headers: {\n    'X-Api-Key': 'YOUR_API_KEY',\n    'Content-Type': 'application\u002Fjson',\n  },\n  body: JSON.stringify({\n    seconds: 900,\n    comment: 'Refined estimate',\n  }),\n})\n\nconst { success, data } = await res.json()\n```\n\n### JavaScript — OAuth application\n\n```javascript\nconst res = await fetch('https:\u002F\u002Fvibecode.bitrix24.com\u002Fv1\u002Ftasks\u002F289\u002Ftime\u002F161', {\n  method: 'PATCH',\n  headers: {\n    'X-Api-Key': 'YOUR_APP_KEY',\n    'Authorization': 'Bearer USER_SESSION_TOKEN',\n    'Content-Type': 'application\u002Fjson',\n  },\n  body: JSON.stringify({\n    seconds: 900,\n    comment: 'Refined estimate',\n  }),\n})\n\nconst { success, data } = await res.json()\n```\n\n## Response fields\n\n| Field | Type | Description |\n|------|-----|---------|\n| `success` | boolean | Always `true` on a successful update |\n| `data.id` | number | ID of the updated entry. For the other fields, see [`GET \u002Fv1\u002Ftasks\u002F:taskId\u002Ftime\u002F:itemId`](.\u002Fget.md) |\n\n## Response example\n\n```json\n{\n  \"success\": true,\n  \"data\": {\n    \"id\": 161\n  }\n}\n```\n\n## Error response example\n\n404 — the entry was not found or is inaccessible:\n\n```json\n{\n  \"success\": false,\n  \"error\": {\n    \"code\": \"NOT_FOUND\",\n    \"message\": \"Time entry not found\"\n  }\n}\n```\n\n## Errors\n\n| HTTP | Code | Description |\n|------|-----|---------|\n| 400 | `READONLY_FIELD` | `userId` was passed — the entry's author cannot be changed (see \"Known specifics\") |\n| 400 | `INVALID_PARAMS` | `taskId` or `itemId` is not a positive integer |\n| 404 | `NOT_FOUND` | An entry with this `itemId` was not found or the parent task is inaccessible |\n| 403 | `SCOPE_DENIED` | The API key lacks the `task` scope |\n| 403 | `WRITE_BLOCKED_READONLY_KEY` | The key is read-only — see [access rights](\u002Fdocs\u002Faccess-rights) |\n| 401 | `TOKEN_MISSING` | The API key has no configured tokens |\n\nFull list of common API errors — [Errors](\u002Fdocs\u002Ferrors).\n\n## Known specifics\n\n**The update applies only `seconds`, `comment` and `createdDate`.** Other body fields are ignored: an empty body, or a body with only such fields, returns `200` and leaves the entry unchanged. The exception is `userId`: a request carrying it is refused entirely, and the `seconds` and `comment` sent alongside are not saved either. The author is fixed when the entry is created. To move tracked time to another employee, delete the entry and create a new one with the desired `userId`.\n\n## See also\n\n- [Get a time-tracking entry](.\u002Fget.md)\n- [List time-tracking entries](.\u002Flist.md)\n- [Add an entry](.\u002Fcreate.md)\n- [Delete a time-tracking entry](.\u002Fdelete.md)\n- [Tasks](\u002Fdocs\u002Fentities\u002Ftasks)\n","\n## Delete a time-tracking entry\n\n`DELETE \u002Fv1\u002Ftasks\u002F:taskId\u002Ftime\u002F:itemId`\n\nDeletes a time-tracking entry. It cannot be restored via the API — create a new one if needed.\n\n## Parameters\n\n| Parameter | Type | Required | Description |\n|----------|-----|:-----:|---------|\n| `taskId` (path) | number | yes | Task ID |\n| `itemId` (path) | number | yes | Time-tracking entry ID |\n\n## Examples\n\n### curl — personal key\n\n```bash\ncurl -X DELETE \"https:\u002F\u002Fvibecode.bitrix24.com\u002Fv1\u002Ftasks\u002F289\u002Ftime\u002F161\" \\\n  -H \"X-Api-Key: YOUR_API_KEY\"\n```\n\n### curl — OAuth application\n\n```bash\ncurl -X DELETE \"https:\u002F\u002Fvibecode.bitrix24.com\u002Fv1\u002Ftasks\u002F289\u002Ftime\u002F161\" \\\n  -H \"X-Api-Key: YOUR_APP_KEY\" \\\n  -H \"Authorization: Bearer USER_SESSION_TOKEN\"\n```\n\n### JavaScript — personal key\n\n```javascript\nconst res = await fetch('https:\u002F\u002Fvibecode.bitrix24.com\u002Fv1\u002Ftasks\u002F289\u002Ftime\u002F161', {\n  method: 'DELETE',\n  headers: {\n    'X-Api-Key': 'YOUR_API_KEY',\n  },\n})\n\nif (res.status === 204) {\n  console.log('Entry deleted')\n}\n```\n\n### JavaScript — OAuth application\n\n```javascript\nconst res = await fetch('https:\u002F\u002Fvibecode.bitrix24.com\u002Fv1\u002Ftasks\u002F289\u002Ftime\u002F161', {\n  method: 'DELETE',\n  headers: {\n    'X-Api-Key': 'YOUR_APP_KEY',\n    'Authorization': 'Bearer USER_SESSION_TOKEN',\n  },\n})\n\nif (res.status === 204) {\n  console.log('Deleted')\n}\n```\n\n## Response\n\nA successful deletion returns HTTP status `204 No Content` with an empty body — check the status code to confirm success.\n\n## Response example\n\n```\nHTTP\u002F1.1 204 No Content\n```\n\n## Error response example\n\n404 — the entry was not found or is inaccessible:\n\n```json\n{\n  \"success\": false,\n  \"error\": {\n    \"code\": \"NOT_FOUND\",\n    \"message\": \"Time entry not found\"\n  }\n}\n```\n\n## Errors\n\n| HTTP | Code | Description |\n|------|-----|---------|\n| 404 | `NOT_FOUND` | An entry with this `itemId` was not found (including if it or the parent task has already been deleted) |\n| 403 | `SCOPE_DENIED` | The API key lacks the `task` scope |\n| 401 | `TOKEN_MISSING` | The API key has no configured tokens |\n\nFull list of common API errors — [Errors](\u002Fdocs\u002Ferrors).\n\n## See also\n\n- [List time-tracking entries](.\u002Flist.md)\n- [Get a time-tracking entry](.\u002Fget.md)\n- [Update a time-tracking entry](.\u002Fupdate.md)\n- [Tasks](\u002Fdocs\u002Fentities\u002Ftasks)\n","\n## List entries across the whole Bitrix24 account\n\n`GET \u002Fv1\u002Ftask-time`\n\nReturns time-tracking entries from all tasks in the Bitrix24 account in a single request, with filtering by employee, period and task. Use it when the list of tasks is not known in advance — for example, for an employee's monthly time report.\n\n## Parameters\n\n| Parameter | Type | Default | Description |\n|----------|-----|-----------|---------|\n| `userId` (query) | number | — | Employee identifier. List: `GET \u002Fv1\u002Fusers`. If omitted, the response includes entries for all employees the key owner can access |\n| `from` (query) | string | — | Lower bound of the period, inclusive, by the `createdDate` field. Accepts ISO 8601 `2026-05-01T00:00:00+00:00` and a plain date `2026-05-01` |\n| `to` (query) | string | — | Upper bound of the period, inclusive, by the `createdDate` field. Same format as `from`. A plain date covers the whole day |\n| `taskId` (query) | number | — | Narrow the result set to a single task, on top of `userId`, `from` and `to`. Identifier: `GET \u002Fv1\u002Ftasks` |\n| `limit` (query) | number | `50` | Page size, from 1 to 500. A value above 500 is clamped to 500 |\n| `offset` (query) | number | `0` | Offset within the result set. Must be a multiple of `limit` |\n\n**Pagination.** A single call returns up to 500 entries. With a `limit` above 50, Vibecode assembles the window server-side and returns it in full. The `offset` value must be a multiple of `limit` — `0`, `limit`, `2 × limit`, and so on, otherwise `400 INVALID_OFFSET` is returned. `meta.hasMore` indicates whether more entries exist beyond the window.\n\n**Filter format.** The generic `filter` envelope is not supported. Use the named query parameters `userId`, `taskId`, `from`, and `to`. Any bracket key `filter[...]`, a non-empty `filter` value, a JSON form including `filter={}`, or a repeated `filter` parameter returns `400 UNSUPPORTED_FILTER`. A single empty `filter=` parameter means no filter and preserves status `200`.\n\n## Examples\n\n### curl — personal key\n\n```bash\ncurl \"https:\u002F\u002Fvibecode.bitrix24.com\u002Fv1\u002Ftask-time?userId=1&from=2026-05-01&to=2026-05-31\" \\\n  -H \"X-Api-Key: YOUR_API_KEY\"\n```\n\n### curl — OAuth application\n\n```bash\ncurl \"https:\u002F\u002Fvibecode.bitrix24.com\u002Fv1\u002Ftask-time?userId=1&from=2026-05-01&to=2026-05-31\" \\\n  -H \"X-Api-Key: YOUR_APP_KEY\" \\\n  -H \"Authorization: Bearer USER_SESSION_TOKEN\"\n```\n\n### JavaScript — personal key\n\n```javascript\nconst url = 'https:\u002F\u002Fvibecode.bitrix24.com\u002Fv1\u002Ftask-time?userId=1&from=2026-05-01&to=2026-05-31'\n\nconst res = await fetch(url, {\n  headers: {\n    'X-Api-Key': 'YOUR_API_KEY',\n  },\n})\n\nconst { success, data, meta } = await res.json()\nconst totalSeconds = data.reduce((sum, r) => sum + r.seconds, 0)\nconsole.log(`For the period: ${totalSeconds \u002F 3600} h, ${meta.total} entries`)\n```\n\n### JavaScript — OAuth application\n\n```javascript\nconst url = 'https:\u002F\u002Fvibecode.bitrix24.com\u002Fv1\u002Ftask-time?userId=1&from=2026-05-01&to=2026-05-31'\n\nconst res = await fetch(url, {\n  headers: {\n    'X-Api-Key': 'YOUR_APP_KEY',\n    'Authorization': 'Bearer USER_SESSION_TOKEN',\n  },\n})\n\nconst { success, data, meta } = await res.json()\n```\n\n## Response fields\n\n| Field | Type | Description |\n|------|-----|---------|\n| `success` | boolean | Always `true` on success |\n| `data` | array | Array of time-tracking entries |\n| `data[].id` | number | Entry identifier |\n| `data[].taskId` | number | Parent task identifier. Card: `GET \u002Fv1\u002Ftasks\u002F:id` |\n| `data[].userId` | number | Entry author. Profile: `GET \u002Fv1\u002Fusers\u002F:userId` |\n| `data[].seconds` | number | Duration in seconds |\n| `data[].minutes` | number | Duration in minutes, derived from `seconds` |\n| `data[].commentText` | string | Comment for the entry. An empty comment is returned as `\"\"` |\n| `data[].source` | string | Source: `2` — REST API |\n| `data[].createdDate` | datetime | When the entry was created |\n| `data[].dateStart` | datetime | Start of the tracked interval, filled automatically |\n| `data[].dateStop` | datetime | End of the tracked interval, filled automatically |\n| `meta.total` | number | Total number of entries matching the filter |\n| `meta.limit` | number | Applied page size |\n| `meta.offset` | number | Applied offset |\n| `meta.hasMore` | boolean | Whether there are more entries beyond the current window |\n\n## Response example\n\n```json\n{\n  \"success\": true,\n  \"data\": [\n    {\n      \"id\": 161,\n      \"taskId\": 3881,\n      \"userId\": 1,\n      \"commentText\": \"Code review\",\n      \"seconds\": 900,\n      \"minutes\": 15,\n      \"source\": \"2\",\n      \"createdDate\": \"2026-05-13T16:15:41+00:00\",\n      \"dateStart\": \"2026-05-13T17:15:41+00:00\",\n      \"dateStop\": \"2026-05-13T17:15:41+00:00\"\n    },\n    {\n      \"id\": 159,\n      \"taskId\": 3867,\n      \"userId\": 1,\n      \"commentText\": \"Build check\",\n      \"seconds\": 600,\n      \"minutes\": 10,\n      \"source\": \"2\",\n      \"createdDate\": \"2026-05-06T10:46:12+00:00\",\n      \"dateStart\": \"2026-05-06T11:46:12+00:00\",\n      \"dateStop\": \"2026-05-06T11:46:12+00:00\"\n    },\n    {\n      \"id\": 157,\n      \"taskId\": 289,\n      \"userId\": 1,\n      \"commentText\": \"Draft preparation\",\n      \"seconds\": 1800,\n      \"minutes\": 30,\n      \"source\": \"2\",\n      \"createdDate\": \"2026-05-06T10:45:47+00:00\",\n      \"dateStart\": \"2026-05-06T11:45:47+00:00\",\n      \"dateStop\": \"2026-05-06T11:45:47+00:00\"\n    }\n  ],\n  \"meta\": {\n    \"total\": 3,\n    \"limit\": 50,\n    \"offset\": 0,\n    \"hasMore\": false\n  }\n}\n```\n\n## Error response example\n\n400 — `userId` is not a positive integer:\n\n```json\n{\n  \"success\": false,\n  \"error\": {\n    \"code\": \"INVALID_USER_ID\",\n    \"message\": \"userId must be a positive integer\"\n  }\n}\n```\n\n## Errors\n\n| HTTP | Code | Description |\n|------|-----|---------|\n| 400 | `INVALID_USER_ID` | `userId` is not a positive integer |\n| 400 | `INVALID_TASK_ID` | `taskId` is not a positive integer |\n| 400 | `INVALID_PARAMS` | `from` or `to` cannot be parsed as a date — `YYYY-MM-DD` and ISO 8601 are accepted |\n| 400 | `INVALID_OFFSET` | `offset` is not a multiple of `limit` — pagination requires the values `0`, `limit`, `2 × limit`, and so on |\n| 400 | `UNSUPPORTED_FILTER` | An unsupported `filter` was provided; use `userId`, `taskId`, `from`, and `to` |\n| 403 | `SCOPE_DENIED` | The API key lacks the `task` scope |\n| 401 | `TOKEN_MISSING` | The API key has no configured tokens |\n\nFull list of common API errors — [Errors](\u002Fdocs\u002Ferrors).\n\n## Known specifics\n\n**Sorted newest to oldest.** The most recently added entries are returned first. `limit` and `offset` work on top of this sort.\n\n**A malformed date is refused up front.** A `from` or `to` value that cannot be parsed as a date answers `400 INVALID_PARAMS` before Bitrix24 is called. It used to be dropped in silence and the whole range came back with status `200`, so a typo in a date read as either \"nothing in that period\" or a full dump. An empty value (`?from=`) still means \"no filter\".\n\n**An offset past the end of the result set.** A request whose `offset` exceeds the number of entries returns an empty array, and `meta.total` in that response echoes the `offset`. Detect the end of the listing by `meta.hasMore` being `false`, not by comparing `offset` with `meta.total`.\n\n## See also\n\n- [List entries of a task](.\u002Flist.md)\n- [Add an entry](.\u002Fcreate.md)\n- [Task time tracking](\u002Fdocs\u002Fentities\u002Ftasks\u002Ftime)\n- [Tasks](\u002Fdocs\u002Fentities\u002Ftasks)\n- [Employees](\u002Fdocs\u002Fentities\u002Fusers)\n- [Limits and optimization](\u002Fdocs\u002Foptimization)\n","\n## Time-tracking entry fields\n\n`GET \u002Fv1\u002Ftask-time\u002Ffields`\n\nReturns the field schema of a time-tracking entry. One schema covers every task, so the path is flat and carries no task identifier.\n\n## Examples\n\n### curl — personal key\n\n```bash\ncurl \"https:\u002F\u002Fvibecode.bitrix24.com\u002Fv1\u002Ftask-time\u002Ffields\" \\\n  -H \"X-Api-Key: YOUR_API_KEY\"\n```\n\n### curl — OAuth application\n\n```bash\ncurl \"https:\u002F\u002Fvibecode.bitrix24.com\u002Fv1\u002Ftask-time\u002Ffields\" \\\n  -H \"X-Api-Key: YOUR_APP_KEY\" \\\n  -H \"Authorization: Bearer USER_SESSION_TOKEN\"\n```\n\n### JavaScript — personal key\n\n```javascript\nconst res = await fetch('https:\u002F\u002Fvibecode.bitrix24.com\u002Fv1\u002Ftask-time\u002Ffields', {\n  headers: {\n    'X-Api-Key': 'YOUR_API_KEY',\n  },\n})\n\nconst { success, data } = await res.json()\nconsole.log('Fields:', Object.keys(data.fields).length)\n```\n\n### JavaScript — OAuth application\n\n```javascript\nconst res = await fetch('https:\u002F\u002Fvibecode.bitrix24.com\u002Fv1\u002Ftask-time\u002Ffields', {\n  headers: {\n    'X-Api-Key': 'YOUR_APP_KEY',\n    'Authorization': 'Bearer USER_SESSION_TOKEN',\n  },\n})\n\nconst { success, data } = await res.json()\n```\n\n## Response fields\n\n| Field | Type | Description |\n|------|-----|---------|\n| `success` | boolean | Always `true` on success |\n| `data.fields` | object | Entry field schema. The key is the field name in camelCase, the value is its descriptor |\n| `data.fields.\u003Cname>.type` | string | Value type of the field: `number`, `string` or `datetime` |\n| `data.fields.\u003Cname>.readonly` | boolean | `true` — the field is filled by the system and is not accepted on write |\n| `data.fields.\u003Cname>.createOnly` | boolean | Present on fields accepted only when an entry is created. In an update request such a field is rejected with `400 READONLY_FIELD` |\n| `data.fields.\u003Cname>.label` | string | Short name of the field |\n| `data.fields.\u003Cname>.description` | string | Explanation of the field, including the key name in the request body when it differs from the name in the response |\n\nThe schema describes ten fields:\n\n| Field | Type | RO | Description |\n|------|-----|:--:|---------|\n| `id` | number | yes | Entry identifier |\n| `taskId` | number | yes | Identifier of the parent task. On the nested paths it is taken from the request path and is not set in the body |\n| `userId` | number | | The employee the time is logged for. List: `GET \u002Fv1\u002Fusers`. Accepted on creation only, and defaults to the key owner |\n| `seconds` | number | | Logged duration in seconds. Required on creation, optional on update |\n| `minutes` | number | yes | Duration in minutes, derived from `seconds` |\n| `commentText` | string | | Comment for the entry. In the request body it is passed under the name `comment`. An empty comment arrives as an empty string |\n| `source` | string | yes | Origin of the entry. The value `2` means the entry was created through the REST API |\n| `createdDate` | datetime | | Creation date in ISO 8601 with the account's UTC offset. Accepted on creation and on update, which lets you backdate an entry |\n| `dateStart` | datetime | yes | Start of the tracked interval in ISO 8601 with the account's UTC offset |\n| `dateStop` | datetime | yes | End of the tracked interval in ISO 8601 with the account's UTC offset |\n\n## Response example\n\n```json\n{\n  \"success\": true,\n  \"data\": {\n    \"fields\": {\n      \"id\": {\n        \"type\": \"number\",\n        \"readonly\": true,\n        \"label\": \"ID\",\n        \"description\": \"Time-entry identifier. Serialized as a number.\"\n      },\n      \"taskId\": {\n        \"type\": \"number\",\n        \"readonly\": true,\n        \"label\": \"Task ID\",\n        \"description\": \"Numeric id of the parent task. Comes from the URL path on the nested routes — not settable in the body.\"\n      },\n      \"userId\": {\n        \"type\": \"number\",\n        \"readonly\": false,\n        \"label\": \"Author ID\",\n        \"description\": \"Numeric id of the user the time is logged for — an id from GET \u002Fv1\u002Fusers. Optional on create (defaults to the key owner); PATCH rejects it with 400 READONLY_FIELD, because Bitrix24 cannot reassign the author.\",\n        \"createOnly\": true\n      },\n      \"seconds\": {\n        \"type\": \"number\",\n        \"readonly\": false,\n        \"label\": \"Seconds\",\n        \"description\": \"Logged duration in seconds. Required on create, optional on update. Body key: seconds.\"\n      },\n      \"minutes\": {\n        \"type\": \"number\",\n        \"readonly\": true,\n        \"label\": \"Minutes\",\n        \"description\": \"Duration in minutes, derived from seconds by Bitrix24. Read-only through this API — the Vibe route never forwards it.\"\n      },\n      \"commentText\": {\n        \"type\": \"string\",\n        \"readonly\": false,\n        \"label\": \"Comment\",\n        \"description\": \"Comment for the entry. On write pass it as comment in the body — commentText is the response name. An empty comment is returned as \\\"\\\", not null.\"\n      },\n      \"source\": {\n        \"type\": \"string\",\n        \"readonly\": true,\n        \"label\": \"Source\",\n        \"description\": \"Origin of the entry, set by Bitrix24: \\\"2\\\" — created through the REST API.\"\n      },\n      \"createdDate\": {\n        \"type\": \"datetime\",\n        \"readonly\": false,\n        \"label\": \"Created at\",\n        \"description\": \"Creation date, ISO 8601 with the account's UTC offset (for example 2026-05-13T16:15:41+00:00). Writable on create and update — pass createdDate to backdate an entry.\"\n      },\n      \"dateStart\": {\n        \"type\": \"datetime\",\n        \"readonly\": true,\n        \"label\": \"Interval start\",\n        \"description\": \"Start of the tracked interval, ISO 8601 with the account's UTC offset. Filled by Bitrix24 automatically and not editable through this API.\"\n      },\n      \"dateStop\": {\n        \"type\": \"datetime\",\n        \"readonly\": true,\n        \"label\": \"Interval end\",\n        \"description\": \"End of the tracked interval, ISO 8601 with the account's UTC offset. Filled by Bitrix24 automatically and not editable through this API.\"\n      }\n    }\n  }\n}\n```\n\n## Error response example\n\n403 — scope missing:\n\n```json\n{\n  \"success\": false,\n  \"error\": {\n    \"code\": \"SCOPE_DENIED\",\n    \"message\": \"This endpoint requires 'task' scope\"\n  }\n}\n```\n\n## Errors\n\n| HTTP | Code | Description |\n|------|-----|---------|\n| 400 | `WRONG_PATH` | The request went to the nested path `GET \u002Fv1\u002Ftasks\u002F:taskId\u002Ftime\u002Ffields`. The correct flat path is named in the error text |\n| 403 | `SCOPE_DENIED` | The key lacks the `task` scope |\n| 401 | `MISSING_API_KEY` | The `X-Api-Key` header was not sent |\n\nFull list of common API errors — [Errors](\u002Fdocs\u002Ferrors).\n\n## Known specifics\n\n**The schema does not depend on the Bitrix24 account.** The response is assembled on the Vibecode platform side and makes no Bitrix24 call along the way. That is why the request only needs the `task` scope — the account's configured tokens are not required for it.\n\n## See also\n\n- [Task time tracking](\u002Fdocs\u002Fentities\u002Ftasks\u002Ftime)\n- [Add an entry](\u002Fdocs\u002Fentities\u002Ftasks\u002Ftime\u002Fcreate)\n- [Update a time-tracking entry](\u002Fdocs\u002Fentities\u002Ftasks\u002Ftime\u002Fupdate)\n- [List entries across the whole Bitrix24 account](\u002Fdocs\u002Fentities\u002Ftasks\u002Ftime\u002Fglobal-list)\n",1794739438435]