---
title: "Bulk save project files"
method: POST
path: "/v1/integration/projects/{projectId}/files/batch-save"
tags: ["Unified Project Lifecycle APIs"]
---

# Bulk save project files

`POST /v1/integration/projects/{projectId}/files/batch-save`

## Request

- Base URL: `https://integration-adapter.connect.cloud.precisely.com`
- URL: `https://integration-adapter.connect.cloud.precisely.com/v1/integration/projects/{projectId}/files/batch-save`
- Auth: HTTP bearer

Bulk saves project files and preserves generated 200 or 207 bulk-operation statuses.
Each file's `content` is a Base64-encoded string. Successful results return metadata;
content is Base64-encoded wherever a content field is included.

**Features:**
- Accepts up to 250 files per batch request (connect-portal's configured maximum).
- Returns per-file results so partial failures do not abort the entire batch.
- Skips the write and returns `unchanged: true` on an item when its submitted content, `mimeType`, and `encoding` already match the stored file (for example, a retried autosave) — this avoids creating unnecessary draft versions.
- Update items (identified by `fileId`) may supply an optional `expectedContentHash` precondition; if it does not match the file's current stored content hash, only that item fails — other items in the batch are unaffected. Ignored for new-file items.

**Use Cases:**
- VS Code extension pushes multiple locally edited files in one request.
- User seeds a project with a directory of generated files.

**Authorization:** Requires `replication-pipeline::create` when permission harmonization is enabled; otherwise, `replication-pipeline::manage`.

## Path parameters

- `projectId` string, required

## Query parameters

- `projectType` 'REPLICATION' | 'MAINFRAME_REPLICATION' | 'ADVANCED_REPLICATION', required: Supported project types for unified project operations
- `pipelineId` string
- `revisionNumber` integer

## Request body

- ProjectFileBulkSaveRequest: Request payload for bulk-saving project files (maximum 250 per request)
  - `files` ProjectFileUpsertRequest[], required: Files to create or update, up to 250 per request
    - `fileId` string: Identifier of an existing file to update. Required for a batch-save item that updates a file; ignored by the single create endpoint, which always creates a new file.
    - `flattenedPath` string: Path of the file within the project's flattened file tree. Required when creating a new file — via the single create endpoint, or as a batch-save item without fileId. Not required when fileId identifies an existing file to update.
    - `content` string: Base64-encoded file content, decoded using the declared encoding
    - `mimeType` string: MIME type of the file content
    - `encoding` string: Encoding used to decode the Base64 content
    - `expectedVersion` integer: Expected current version, used for optimistic concurrency when overwriting
    - `expectedContentHash` string: Optional content-hash precondition, checked only when this item updates an existing file (fileId supplied). If it does not match the file's current stored hash, only this item fails; other items are unaffected. Ignored when creating a new file.

## Response `200`

All files saved successfully

- ProjectFileBatchResultResponse: Results for a bulk file save or delete operation
  - `results` ProjectFileBatchItemResponse[]: Per-file results, in request order
    - `fileId` string: Unique identifier of the file
    - `successful` boolean: Whether this file's operation succeeded
    - `error` string: Failure reason, present only when successful is false
    - `metadata` ProjectFileSummaryResponse: Project file metadata. Content is intentionally omitted.
      - `fileId` string: Unique identifier of the file
      - `dataFlowId` string: Advanced Replication dataflow identifier owning this file, when applicable
      - `fileName` string: File name derived from the flattened path
      - `flattenedPath` string: Path of the file within the project's flattened file tree
      - `version` integer: Current version number of the file
      - `phase` 'DRAFT' | 'APPROVED' | 'PENDING_DELETION': Lifecycle phase of the file
      - `mimeType` string: MIME type of the file content
      - `encoding` string: Encoding of the file content
      - `sizeBytes` integer: Size of the file content in bytes
      - `contentHash` string: Hash of the file content, used for change detection
      - `entryFile` boolean: Whether this file is the project's designated entry file
      - `unchanged` boolean: True when an update matched the stored file and no write was performed; omitted for read (list/get) and create/delete responses
    - `unchanged` boolean: True when this update item matched the stored file and no write was performed; omitted for create and delete items

## Other responses

- `207`: One or more file saves failed
- `400`: Bad Request — batch size exceeds the maximum allowed (DI-ADAPTER-PRF-0006), or the resolved project type does not support files (DI-ADAPTER-PRF-0009)
- `401`: Unauthorized
- `403`: Forbidden — requires replication-pipeline::create when permission harmonization is enabled, or legacy replication-pipeline::manage otherwise
- `404`: Not Found — project does not exist (DI-ADAPTER-PRF-0001)
- `409`: Conflict — the project has a commit in progress, so file operations are temporarily blocked until it finishes (DI-ADAPTER-PRF-0005)
- `500`: Internal Server Error — batch save failed (DI-ADAPTER-PRF-0002)

---

[API](https://skmtc.dev/precisely/apis/precisely-integration-adapter-service.md) · [All operations](https://skmtc.dev/precisely/apis/precisely-integration-adapter-service/llms.txt) · [OpenAPI document](https://skmtc.dev/precisely/apis/precisely-integration-adapter-service/revisions/2d2629f4987d?raw)
