# Complete an upload

`POST https://api-vod-express.syncwords.com/v1/projects/{id}/uploads/{uploadId}/complete`

Complete an upload

Assembles the parts: the file is now in `input/`, and a running project picks it up. A project that ran before and is `stopped` now (auto-stopped after its last file, or stopped by hand) is started again, unless its `startOnNewFiles` is false; one that never ran (`autoStart: false`) or is in `error` is left as it is, and `projectStatus` says which. Replacing a file (`overwrite`) also drops what was recorded about the old one, so the new one is processed from scratch. Safe to repeat with the same body.

**Guide:** [Upload through the API](/vod-express/uploads/api-uploads)

## Parameters

| Name | In | Type | Required | Description |
|---|---|---|---|---|
| `id` | path | string | yes | The project id, a lowercase ULID. |
| `uploadId` | path | string | yes | The `uploadId` `POST /projects/{id}/uploads` answered, URL-encoded. |

## Request body

Example:

```json
{
  "key": "season 2/episode 01.mp4",
  "parts": [
    {
      "partNumber": 1,
      "etag": "\"08b46181d7094b5ece88bb389c7499af\""
    },
    {
      "partNumber": 2,
      "etag": "\"5d41402abc4b2a76b9719d911017c592\""
    }
  ]
}
```

Schema:

```json
{
  "type": "object",
  "required": [
    "key",
    "parts"
  ],
  "additionalProperties": false,
  "properties": {
    "key": {
      "type": "string",
      "description": "The `key` the upload started with."
    },
    "parts": {
      "type": "array",
      "minItems": 1,
      "maxItems": 10000,
      "description": "Every part, the ones listed by `GET …/parts` included.",
      "items": {
        "type": "object",
        "required": [
          "partNumber",
          "etag"
        ],
        "properties": {
          "partNumber": {
            "type": "integer",
            "minimum": 1,
            "maximum": 10000
          },
          "etag": {
            "type": "string",
            "description": "The `ETag` header S3 answered the part’s `PUT` with, quoted or not."
          }
        }
      }
    }
  }
}
```

## Responses

### 200

Complete

Example:

```json
{
  "data": {
    "key": "season 2/episode 01.mp4",
    "projectStatus": "running"
  }
}
```

Schema:

```json
{
  "type": "object",
  "required": [
    "data"
  ],
  "properties": {
    "data": {
      "type": "object",
      "required": [
        "key",
        "projectStatus"
      ],
      "properties": {
        "key": {
          "type": "string"
        },
        "projectStatus": {
          "enum": [
            "running",
            "stopped",
            "error"
          ],
          "description": "The project’s state after the call. `running`: the file will be processed. `stopped`: the project never ran; start it when every file is uploaded. `error`: its last start failed; see `GET …/status`, then `POST …/start`."
        }
      }
    }
  }
}
```

### 401

No token, or an expired or unknown one: `unauthenticated`.

Example:

```json
{
  "message": "Unauthenticated.",
  "code": "unauthenticated"
}
```

Schema:

```json
{
  "$ref": "#/components/schemas/Error"
}
```

### 403

VOD Express is not available to the account: switched off for it (`vod_express_not_enabled`), or the account is restricted — its access revoked, its trial expired or used up (`account_restricted`, with the reason in `message`).

Example:

```json
{
  "message": [
    "VOD Express is not enabled for your account."
  ],
  "code": "vod_express_not_enabled"
}
```

Schema:

```json
{
  "$ref": "#/components/schemas/Error"
}
```

### 404

No such project, or no such upload for that key — completed, aborted, expired or never started: `upload_not_found`.

Example:

```json
{
  "message": "Upload not found.",
  "code": "upload_not_found"
}
```

Schema:

```json
{
  "$ref": "#/components/schemas/Error"
}
```

### 413

The body is over 2 MB: `payload_too_large`.

Example:

```json
{
  "message": [
    "The request body is too large."
  ],
  "code": "payload_too_large"
}
```

Schema:

```json
{
  "$ref": "#/components/schemas/Error"
}
```

### 415

The body is neither JSON nor YAML: `unsupported_media_type`.

Example:

```json
{
  "message": [
    "Send the body as JSON (Content-Type: application/json) or YAML (Content-Type: application/yaml)."
  ],
  "code": "unsupported_media_type"
}
```

Schema:

```json
{
  "$ref": "#/components/schemas/Error"
}
```

### 422

An invalid body, or parts S3 refuses — a wrong ETag, a part it does not hold, a part under 5 MiB other than the last: `validation_failed`, under `errors.parts`.

Schema:

```json
{
  "$ref": "#/components/schemas/Error"
}
```

### 429

Rate limited: `too_many_requests`. Wait the seconds `Retry-After` says, then repeat the call.

Example:

```json
{
  "message": [
    "Too Many Attempts."
  ],
  "code": "too_many_requests"
}
```

Schema:

```json
{
  "$ref": "#/components/schemas/Error"
}
```

## Schemas

### Error

`#/components/schemas/Error`

```json
{
  "type": "object",
  "required": [
    "message",
    "code"
  ],
  "properties": {
    "message": {
      "description": "For people. A string, or an array of one string on some statuses: read it as `Array.isArray(m) ? m[0] : m`.",
      "oneOf": [
        {
          "type": "string"
        },
        {
          "type": "array",
          "items": {
            "type": "string"
          }
        }
      ]
    },
    "code": {
      "description": "For programs: stable, one per situation. See the Errors guide.",
      "enum": [
        "bad_request",
        "invalid_output_path",
        "invalid_idempotency_key",
        "unauthenticated",
        "invalid_credentials",
        "forbidden",
        "vod_express_not_enabled",
        "account_restricted",
        "not_found",
        "project_not_found",
        "file_not_found",
        "file_meta_not_found",
        "output_not_found",
        "feed_not_found",
        "upload_not_found",
        "webhook_not_found",
        "webhook_delivery_not_found",
        "aws_access_not_provisioned",
        "storage_connection_not_found",
        "method_not_allowed",
        "conflict",
        "file_exists",
        "project_reads_feed",
        "project_reads_folder",
        "file_processing",
        "project_config_locked",
        "idempotency_in_progress",
        "storage_connection_in_use",
        "payload_too_large",
        "unsupported_media_type",
        "validation_failed",
        "service_start_failed",
        "idempotency_key_reused",
        "webhook_limit_reached",
        "storage_failed",
        "storage_connection_check_failed",
        "storage_connection_folder_only",
        "storage_prefix_taken",
        "build_without_storage_connections",
        "build_has_no_schema",
        "too_many_requests",
        "internal_error",
        "bad_gateway",
        "service_stop_failed",
        "aws_access_failed",
        "platform_unavailable",
        "service_unavailable",
        "build_list_unavailable"
      ]
    },
    "errors": {
      "type": "object",
      "description": "On a 422: each field’s messages, keyed by field name, or by JSON pointer inside `config`.",
      "additionalProperties": {
        "type": "array",
        "items": {
          "type": "string"
        }
      }
    }
  }
}
```
