[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"docs-recipes\u002Fdisk-files":3,"docs-tabs-recipes\u002Fdisk-files":6},{"content":4,"lastmod":5},"# Работа с файлами Диска\n\n**Сложность:** beginner | **Скоупы:** disk | **Стек:** cURL \u002F Node.js\n\n## Что делаем\nУправляем хранилищами, папками и файлами Bitrix24 Диска через Entity API. Получаем список хранилищ, просматриваем содержимое корневой папки (через обходной путь), создаём подпапки, получаем информацию о файлах. Примеры даны в cURL и Node.js.\n\n> **Ограничение:** загрузка файлов (`disk.folder.uploadfile`) пока не покрывается Entity API. Этот метод требует multipart-загрузку и не имеет entity-обёртки. Когда обёртка появится, рецепт будет обновлён.\n\n## Доступные entity-эндпоинты\n\n| Entity | Эндпоинт | Операции |\n|--------|----------|----------|\n| **storages** | `GET \u002Fv1\u002Fstorages`, `GET \u002Fv1\u002Fstorages\u002F:id` | list, get (только чтение) |\n| **folders** | `GET \u002Fv1\u002Ffolders`, `GET \u002Fv1\u002Ffolders\u002F:id`, `POST \u002Fv1\u002Ffolders`, `PATCH \u002Fv1\u002Ffolders\u002F:id`, `DELETE \u002Fv1\u002Ffolders\u002F:id` | list, get, create, update, delete |\n| **files** | `GET \u002Fv1\u002Ffiles`, `GET \u002Fv1\u002Ffiles\u002F:id`, `PATCH \u002Fv1\u002Ffiles\u002F:id`, `DELETE \u002Fv1\u002Ffiles\u002F:id` | list, get, update, delete (без create) |\n\n## Необходимо\n- API-ключ Вайбкод с правами `disk`\n- cURL (установлен в большинстве ОС) или Node.js 18+\n\n## Полный код\n```bash\n#!\u002Fbin\u002Fbash\n# disk-operations.sh\n# Операции с Bitrix24 Диском через Entity API\n\nAPI_KEY=\"${VIBE_API_KEY}\"\nBASE_URL=\"${VIBE_BASE_URL}\"\n\n# ──────────────────────────────────────────\n# 1. Получаем список хранилищ\n#    GET \u002Fv1\u002Fstorages\n# ──────────────────────────────────────────\necho \"Список хранилищ:\"\n\ncurl -s -H \"X-Api-Key: ${API_KEY}\" \\\n  \"${BASE_URL}\u002Fv1\u002Fstorages\" | python3 -m json.tool\n\n# Ответ содержит поля: id, name, entityType, entityId, rootObjectId\n# rootObjectId — это ID корневой папки хранилища (нужен дальше)\n\n# ──────────────────────────────────────────\n# 2. Получаем конкретное хранилище и его rootObjectId\n#    GET \u002Fv1\u002Fstorages\u002F:id\n# ──────────────────────────────────────────\nSTORAGE_ID=1\n\necho -e \"\\nХранилище #${STORAGE_ID}:\"\n\ncurl -s -H \"X-Api-Key: ${API_KEY}\" \\\n  \"${BASE_URL}\u002Fv1\u002Fstorages\u002F${STORAGE_ID}\" | python3 -m json.tool\n\n# ──────────────────────────────────────────\n# 3. Содержимое корневой папки хранилища\n#    Метода disk.storage.getchildren нет в Entity API.\n#    Обходной путь: берём rootObjectId из хранилища\n#    и запрашиваем GET \u002Fv1\u002Ffolders?filter[parentId]=ROOT_OBJECT_ID\n# ──────────────────────────────────────────\nROOT_FOLDER_ID=3  # rootObjectId из шага 2\n\necho -e \"\\nСодержимое корневой папки #${ROOT_FOLDER_ID}:\"\n\ncurl -s -H \"X-Api-Key: ${API_KEY}\" \\\n  \"${BASE_URL}\u002Fv1\u002Ffolders?filter[parentId]=${ROOT_FOLDER_ID}\" | python3 -m json.tool\n\n# ──────────────────────────────────────────\n# 4. Создаём подпапку\n#    POST \u002Fv1\u002Ffolders\n#    parentId — ID родительской папки (rootObjectId или любая другая)\n# ──────────────────────────────────────────\necho -e \"\\nСоздаём папку 'Документы клиентов':\"\n\ncurl -s -X POST \"${BASE_URL}\u002Fv1\u002Ffolders\" \\\n  -H \"X-Api-Key: ${API_KEY}\" \\\n  -H \"Content-Type: application\u002Fjson\" \\\n  -d \"{\n    \\\"parentId\\\": ${ROOT_FOLDER_ID},\n    \\\"name\\\": \\\"Документы клиентов\\\"\n  }\" | python3 -m json.tool\n\n# ──────────────────────────────────────────\n# 5. Список файлов\n#    GET \u002Fv1\u002Ffiles\n# ──────────────────────────────────────────\necho -e \"\\nФайлы на диске:\"\n\ncurl -s -H \"X-Api-Key: ${API_KEY}\" \\\n  \"${BASE_URL}\u002Fv1\u002Ffiles?limit=10\" | python3 -m json.tool\n\n# ──────────────────────────────────────────\n# 6. Информация о конкретном файле\n#    GET \u002Fv1\u002Ffiles\u002F:id\n# ──────────────────────────────────────────\nFILE_ID=42\n\necho -e \"\\nФайл #${FILE_ID}:\"\n\ncurl -s -H \"X-Api-Key: ${API_KEY}\" \\\n  \"${BASE_URL}\u002Fv1\u002Ffiles\u002F${FILE_ID}\" | python3 -m json.tool\n\n# ──────────────────────────────────────────\n# 7. Пакетный запрос: получить хранилища + файлы за один вызов\n#    POST \u002Fv1\u002Fbatch (entity-формат)\n# ──────────────────────────────────────────\necho -e \"\\nПакетный запрос — хранилища + файлы:\"\n\ncurl -s -X POST \"${BASE_URL}\u002Fv1\u002Fbatch\" \\\n  -H \"X-Api-Key: ${API_KEY}\" \\\n  -H \"Content-Type: application\u002Fjson\" \\\n  -d '{\n    \"calls\": [\n      { \"entity\": \"storages\", \"action\": \"list\" },\n      { \"entity\": \"files\", \"action\": \"list\", \"params\": { \"limit\": 5 } }\n    ]\n  }' | python3 -m json.tool\n```\n\n```javascript\n\u002F\u002F disk-operations.js\n\u002F\u002F Node.js: работа с Диском через Entity API\n\nconst API_KEY = process.env.VIBE_API_KEY;\nconst BASE_URL = process.env.VIBE_BASE_URL;\n\nconst HEADERS = {\n  'X-Api-Key': API_KEY,\n  'Content-Type': 'application\u002Fjson',\n};\n\n\u002F\u002F Хелпер для GET-запросов\nasync function apiGet(path) {\n  const response = await fetch(`${BASE_URL}${path}`, {\n    headers: { 'X-Api-Key': API_KEY },\n  });\n  return response.json();\n}\n\n\u002F\u002F Хелпер для POST-запросов\nasync function apiPost(path, body) {\n  const response = await fetch(`${BASE_URL}${path}`, {\n    method: 'POST',\n    headers: HEADERS,\n    body: JSON.stringify(body),\n  });\n  return response.json();\n}\n\n\u002F\u002F 1. Список хранилищ (GET \u002Fv1\u002Fstorages)\nasync function listStorages() {\n  console.log('Хранилища:');\n  const { data } = await apiGet('\u002Fv1\u002Fstorages');\n\n  for (const s of data) {\n    console.log(`  [${s.id}] ${s.name} (${s.entityType}) — корневая папка: ${s.rootObjectId}`);\n  }\n  return data;\n}\n\n\u002F\u002F 2. Содержимое корневой папки хранилища\n\u002F\u002F    Обходной путь: storage.rootObjectId → GET \u002Fv1\u002Ffolders?filter[parentId]=...\nasync function listStorageRootContents(storageId) {\n  console.log(`\\nСодержимое хранилища #${storageId}:`);\n\n  \u002F\u002F Получаем хранилище, чтобы узнать rootObjectId\n  const { data: storage } = await apiGet(`\u002Fv1\u002Fstorages\u002F${storageId}`);\n  const rootFolderId = storage.rootObjectId;\n\n  console.log(`  Корневая папка: #${rootFolderId}`);\n\n  \u002F\u002F Запрашиваем дочерние элементы корневой папки\n  const { data: children } = await apiGet(\n    `\u002Fv1\u002Ffolders?filter[parentId]=${rootFolderId}`\n  );\n\n  for (const item of children) {\n    console.log(`  [${item.id}] ${item.name}`);\n  }\n  return { rootFolderId, children };\n}\n\n\u002F\u002F 3. Создание подпапки (POST \u002Fv1\u002Ffolders)\nasync function createFolder(parentId, folderName) {\n  console.log(`\\nСоздаём папку \"${folderName}\" в папке #${parentId}...`);\n\n  const { data } = await apiPost('\u002Fv1\u002Ffolders', {\n    parentId,\n    name: folderName,\n  });\n\n  console.log(`  Папка создана: id=${data.id}`);\n  return data;\n}\n\n\u002F\u002F 4. Информация о файле (GET \u002Fv1\u002Ffiles\u002F:id)\nasync function getFileInfo(fileId) {\n  const { data } = await apiGet(`\u002Fv1\u002Ffiles\u002F${fileId}`);\n  console.log(`\\nФайл #${fileId}: ${data.name} (${data.size} байт)`);\n  return data;\n}\n\n\u002F\u002F 5. Список файлов с фильтром (GET \u002Fv1\u002Ffiles)\nasync function listFiles(folderId) {\n  console.log(`\\nФайлы в папке #${folderId}:`);\n\n  const { data } = await apiGet(\n    `\u002Fv1\u002Ffiles?filter[folderId]=${folderId}`\n  );\n\n  for (const f of data) {\n    console.log(`  [${f.id}] ${f.name} — ${f.size} байт`);\n  }\n  return data;\n}\n\n\u002F\u002F 6. Пакетный запрос: хранилища + файлы за один вызов\n\u002F\u002F    POST \u002Fv1\u002Fbatch (entity-формат)\nasync function batchDiskInfo() {\n  console.log('\\nПакетный запрос:');\n\n  const result = await apiPost('\u002Fv1\u002Fbatch', {\n    calls: [\n      { entity: 'storages', action: 'list' },\n      { entity: 'files', action: 'list', params: { limit: 5 } },\n    ],\n  });\n\n  const [storagesResult, filesResult] = result.data.results;\n\n  console.log(`  Хранилищ: ${storagesResult.data?.length ?? 0}`);\n  console.log(`  Файлов (первые 5): ${filesResult.data?.length ?? 0}`);\n  return result.data;\n}\n\n\u002F\u002F 7. Переименование файла (PATCH \u002Fv1\u002Ffiles\u002F:id)\nasync function renameFile(fileId, newName) {\n  console.log(`\\nПереименование файла #${fileId} → \"${newName}\"...`);\n\n  const response = await fetch(`${BASE_URL}\u002Fv1\u002Ffiles\u002F${fileId}`, {\n    method: 'PATCH',\n    headers: HEADERS,\n    body: JSON.stringify({ name: newName }),\n  });\n\n  const { data } = await response.json();\n  console.log(`  Готово: ${data.name}`);\n  return data;\n}\n\n\u002F\u002F Демонстрация\nasync function demo() {\n  \u002F\u002F Список хранилищ\n  const storages = await listStorages();\n  if (storages.length === 0) {\n    console.log('Хранилищ не найдено');\n    return;\n  }\n\n  \u002F\u002F Содержимое корневой папки первого хранилища\n  const storageId = storages[0].id;\n  const { rootFolderId } = await listStorageRootContents(storageId);\n\n  \u002F\u002F Создаём папку в корне хранилища\n  const folder = await createFolder(rootFolderId, `Проект_${Date.now()}`);\n\n  \u002F\u002F Пакетный запрос\n  await batchDiskInfo();\n\n  console.log('\\nВсе операции выполнены.');\n  console.log('Загрузка файлов (disk.folder.uploadfile) пока не поддерживается через Entity API.');\n}\n\ndemo().catch(console.error);\n```\n\n## Как это работает\n\n1. **Список хранилищ** — `GET \u002Fv1\u002Fstorages` возвращает все доступные хранилища (личное, общее, хранилища отделов). Ключевое поле: `rootObjectId` — ID корневой папки.\n\n2. **Содержимое хранилища** — прямого эндпоинта `disk.storage.getchildren` в Entity API нет. Обходной путь:\n   - Получаем хранилище: `GET \u002Fv1\u002Fstorages\u002F:id`\n   - Извлекаем `rootObjectId`\n   - Запрашиваем содержимое: `GET \u002Fv1\u002Ffolders?filter[parentId]=\u003CrootObjectId>`\n\n3. **Создание папки** — `POST \u002Fv1\u002Ffolders` с параметрами `parentId` и `name`. Можно создавать вложенные структуры, указывая ID родительской папки.\n\n4. **Работа с файлами** — `GET \u002Fv1\u002Ffiles` (список), `GET \u002Fv1\u002Ffiles\u002F:id` (информация), `PATCH \u002Fv1\u002Ffiles\u002F:id` (переименование), `DELETE \u002Fv1\u002Ffiles\u002F:id` (удаление).\n\n5. **Пакетные запросы** — `POST \u002Fv1\u002Fbatch` принимает entity-формат: `{ entity: \"storages\", action: \"list\" }`. До 50 вызовов за один запрос, одна единица rate-limit.\n\n## Ограничения\n\n| Операция | Статус | Комментарий |\n|----------|--------|-------------|\n| Загрузка файла (`disk.folder.uploadfile`) | Недоступна | Метод требует multipart-загрузку, entity-обёртки нет |\n| `disk.storage.getchildren` | Недоступна | Используйте обходной путь через `rootObjectId` + `GET \u002Fv1\u002Ffolders` |\n| Создание файла (`POST \u002Fv1\u002Ffiles`) | Недоступна | Файлы создаются только через загрузку |\n| Создание\u002Fизменение хранилища | Недоступна | Хранилища доступны только для чтения |\n\n## Что можно улучшить\n- Добавить рекурсивный обход вложенных папок для полной структуры диска\n- Автоматически создавать структуру папок по шаблону (например, для каждого клиента)\n- Комбинировать с CRM: при создании сделки автоматически создавать папку и добавлять комментарий в таймлайн с ссылкой на неё\n","2026-06-24",{}]