# Start Upload Group

> Part of the [SpatialGen API documentation](/index.md). [HTML version of this page](/api/direct-upload/start/).

Create a direct upload group and register all files that belong to one video asset set.

## API context

-   API requests use `https://spatialgen.com` with the `/api` path prefix, included once.
-   Authenticate requests to SpatialGen API endpoints with the `X-SPATIALGEN-APPKEY` HTTP header.
-   Use a key from the workspace that owns the requested resources. Follow the roles and scopes specified for each endpoint below.
-   Keep `admin` and `upload` keys on a trusted backend. `readonly` keys may be used in client apps for permitted read operations.
-   Presigned upload URLs have their own authorization. Do not send your SpatialGen API key to those URLs.

See the [API key guide](/guides/get-started.md) for roles, key creation, expiration, revocation, and rotation.

* * *

**POST** `/api/videos/uploads`

Create a new direct upload group for one SpatialGen video asset set and register every file that will be uploaded into that group.

Allowed API Key Roles

`admin`, `upload`

## Request Body

-   `videoName`: string, required
-   `description`: string, optional
-   `layout`: `"2D" | "MVHEVC" | "SBS" | "TB" | "Separate" | "AIV"`, required
-   `perspective`: `"Regular" | "180" | "360"`, optional
-   `folderName`: string, optional
-   `files`: array, required, minimum 1 item

Each `files[]` item accepts:

-   `fileName`: string, required
-   `fileRole`: `"video" | "video_left" | "video_right" | "audio" | "subtitle" | "aime" | "fcpxmld"`, required
-   `sizeBytes`: positive integer, required
-   `languageTag`: string, required for `audio` and `subtitle`, omitted for all other file roles

## Validation Rules

### Layout Rules

-   `Separate` requires exactly one `video_left` file and exactly one `video_right` file.
-   `Separate` does not allow `video`.
-   All other layouts require exactly one `video` file.
-   Non-`Separate` layouts do not allow `video_left` or `video_right`.
-   `AIV` must use perspective `180`.
-   `AIV` requires either one `video` file ending in `.aivu`, or both an `aime` file and an `fcpxmld` file.

### File Extension Rules

-   `video`: `.aivu`, `.mp4`, or `.mov`
-   `video_left`, `video_right`: `.mp4` or `.mov`
-   `audio`: `.mp4` or `.m4a`
-   `subtitle`: `.srt`
-   `aime`: `.aime`
-   `fcpxmld`: `.zip`

### Metadata File Count Rules

-   At most one `aime` file is allowed per upload group.
-   At most one `fcpxmld` file is allowed per upload group.

### Language Code Rules

-   `audio.languageTag` must be one of SpatialGen’s supported language-only tags.
-   `subtitle.languageTag` must be one of SpatialGen’s supported language-only tags.
-   Tags are normalized to lowercase before validation.
-   `audio` accepts the same shared language list used in the SpatialGen dashboard, plus `zxx` for instrumental audio.
-   `subtitle` accepts the shared spoken-language list and does not accept `zxx`.

Supported language tags include:

-   `en`, `es`, `fr`, `de`, `it`, `ja`, `ko`, `pt`, `ru`, `zh`
-   `af`, `am`, `ar`, `az`, `bg`, `bn`, `bs`, `ca`, `cs`, `da`
-   `el`, `et`, `fa`, `fi`, `gu`, `he`, `hi`, `hr`, `hu`, `hy`
-   `id`, `is`, `ka`, `kn`, `lt`, `lv`, `ml`, `mr`, `ms`, `nl`
-   `no`, `pa`, `pl`, `ro`, `sk`, `sl`, `sq`, `sr`, `sv`, `sw`
-   `ta`, `te`, `th`, `tl`, `tr`, `uk`, `ur`, `vi`
-   `zxx` for instrumental audio only

## Response Shape

-   `sessionId`: string
-   `expiresAt`: string
-   `videoName`: string
-   `fileCount`: number
-   `files`: array of registered upload files

Each returned file includes:

-   `uploadId`: string
-   `fileRole`: string
-   `fileName`: string
-   `totalBytes`: number
-   `partSizeBytes`: number
-   `totalParts`: number
-   `uploadStrategy`: `"single_put" | "multipart"`
-   `status`: string

## Example Request

start-upload.js

```js
fetch('https://spatialgen.com/api/videos/uploads', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
    'X-SPATIALGEN-APPKEY': apiKey,
  },
  body: JSON.stringify({
    videoName: 'My Spatial Video',
    description: 'Uploaded from our media pipeline',
    layout: 'Separate',
    perspective: 'Regular',
    folderName: 'Launch Assets',
    files: [
      {
        fileName: 'left-eye.mov',
        fileRole: 'video_left',
        sizeBytes: 1287340032,
      },
      {
        fileName: 'right-eye.mov',
        fileRole: 'video_right',
        sizeBytes: 1287341024,
      },
      {
        fileName: 'english-audio.mp4',
        fileRole: 'audio',
        sizeBytes: 187340032,
        languageTag: 'en',
      },
      {
        fileName: 'english-subtitles.srt',
        fileRole: 'subtitle',
        sizeBytes: 2401,
        languageTag: 'en',
      },
    ],
  }),
})
```

## Example Response

start-response.json

```json
{
  "sessionId": "5ea97a59-95e0-4c8b-a634-b0fa9976f6ff",
  "expiresAt": "2026-05-06T18:42:11.000Z",
  "videoName": "My Spatial Video",
  "fileCount": 4,
  "files": [
    {
      "uploadId": "402f0bda-a0fa-4551-ae28-7300ab6678dd",
      "fileRole": "video_left",
      "fileName": "left-eye.mov",
      "totalBytes": 1287340032,
      "partSizeBytes": 104857600,
      "totalParts": 13,
      "uploadStrategy": "multipart",
      "status": "initialized"
    },
    {
      "uploadId": "87ca2d60-52d4-4c36-a5d0-42b9f95b58ba",
      "fileRole": "video_right",
      "fileName": "right-eye.mov",
      "totalBytes": 1287341024,
      "partSizeBytes": 104857600,
      "totalParts": 13,
      "uploadStrategy": "multipart",
      "status": "initialized"
    },
    {
      "uploadId": "f56c0c54-f212-49b2-90f9-56653791f82b",
      "fileRole": "audio",
      "fileName": "english-audio.mp4",
      "totalBytes": 187340032,
      "partSizeBytes": 104857600,
      "totalParts": 2,
      "uploadStrategy": "multipart",
      "status": "initialized"
    },
    {
      "uploadId": "7fc29357-7475-4422-987f-a17d5524d18e",
      "fileRole": "subtitle",
      "fileName": "english-subtitles.srt",
      "totalBytes": 2401,
      "partSizeBytes": 2401,
      "totalParts": 1,
      "uploadStrategy": "single_put",
      "status": "initialized"
    }
  ]
}
```
