> ## Documentation Index
> Fetch the complete documentation index at: https://docs.genviral.io/llms.txt
> Use this file to discover all available pages before exploring further.

# Add Editor Files

> Append uploaded videos to the end of an existing video project.

Appends finalized uploaded videos to a project you already have and returns the updated project.
Upload and finalize each video with [Upload File](/api-reference/upload-file) first, then pass
their file ids here in the order they should play.

Each file plays in full, starting where the last clip on the base video lane ends. Existing clips
are not moved, trimmed, or re-timed. A file that is not in the project yet becomes a new asset
whose `asset_id` is its file id; a file that is already in the project is placed again, reusing its
asset. The request is atomic: if any file id is refused, nothing is added.

To start a new project from videos instead, use
[Create Editor Project](/api-reference/create-editor-project).

## Concurrency

Pass `expected_updated_at` with the `updated_at` you last read. If the project changed since, the
request is refused with `409 editor_conflict`: read the project again and retry with a new
`Idempotency-Key`.

While Vira (the Genviral assistant) is editing the same project, the request is refused with
`409 editor_locked`. Wait a few seconds and retry.

## Idempotency

`Idempotency-Key` is required and is scoped to the API key (or MCP grant) that sends it.

* Retrying with the same key and the same body returns the project and never appends the files
  twice.
* Reusing a key with a different body returns `409 idempotency_key_reused`.
* A refused request (for example `422 file_not_found`) does not consume its key.

## Path Parameters

<ParamField path="projectId" type="string (UUID)" required>
  The project id.
</ParamField>

## Body Parameters

<ParamField body="file_ids" type="string[]" required>
  1 to 20 finalized video file ids, appended in this order. A repeated id is placed again.
</ParamField>

<ParamField body="expected_updated_at" type="string">
  The `updated_at` you last read (ISO 8601). The request is refused with `editor_conflict` if the
  project changed since.
</ParamField>

## Response

Returns `200` with the updated project, in the same shape as
[Get Editor Project](/api-reference/get-editor-project). Any earlier render is no longer current
for the new cut.

<RequestExample>
  ```bash cURL theme={null}
  curl --request POST \
    --url https://www.genviral.io/api/partner/v1/editor/projects/b1d4e8f2-3a5c-4d7e-8f90-1a2b3c4d5e6f/files \
    --header 'Authorization: Bearer <token>' \
    --header 'Content-Type: application/json' \
    --header 'Idempotency-Key: 0f6d2b84-5c3e-4a19-9d7b-2e8c1a4f6b53' \
    --data '{
      "file_ids": ["7c2e9a14-3b5d-4f60-8a1e-9d0b2c4e6f81"],
      "expected_updated_at": "2026-10-02T12:03:00.000Z"
    }'
  ```
</RequestExample>

<ResponseExample>
  ```json Response theme={null}
  {
    "ok": true,
    "code": 200,
    "message": "Editor files added",
    "data": {
      "project_id": "b1d4e8f2-3a5c-4d7e-8f90-1a2b3c4d5e6f",
      "title": "Launch cut",
      "aspect_ratio": "9:16",
      "duration_ms": 37100,
      "updated_at": "2026-10-02T12:05:00.000Z",
      "assets": [],
      "clips": [],
      "render": null,
      "editor_url": "https://www.genviral.io/editor/b1d4e8f2-3a5c-4d7e-8f90-1a2b3c4d5e6f?workspace=personal"
    }
  }
  ```
</ResponseExample>

## Error Responses

* `400 invalid_json` - request body is not valid JSON
* `400 invalid_request` - `Idempotency-Key` header is missing or longer than 255 characters
* `401` - authentication failed (missing/invalid/revoked token)
* `404 project_not_found` - the project does not exist in the key scope
* `409 editor_locked` - Vira is editing this project right now; retry shortly
* `409 editor_conflict` - the project changed since `expected_updated_at`; read it again
* `409 idempotency_key_reused` - this `Idempotency-Key` was already used with a different body
* `409 request_in_progress` - an identical request with this key is still being processed; retry shortly
* `422 invalid_payload` - body failed validation (see `issues`)
* `422 file_not_found` - one or more file ids are not finalized videos in the key scope; the message lists them
* `422 invalid_document` - the project could not be read or the result would not be a valid project


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.