# Complete multipart upload

`POST /uploads/complete-multipart.json`

Completes the multipart upload in the external store, and copies the
file from its temporary location to its final location in the store.
All of the parts must have been uploaded to the external storage provider.
An Upload record will be completed in most cases once the file is copied
to its final location.

You must have the correct permissions and CORS settings configured in your
external provider. We support AWS S3 as the default. See:

https://meta.discourse.org/t/-/210469#s3-multipart-direct-uploads-4.

An external file store must be set up and `enable_direct_s3_uploads` must
be set to true for this endpoint to function.



Authentication: no security requirement declared for this operation.

Request body: application/json

Type: any

- `unique_identifier` (required)
  Type: string
  
  The unique identifier returned in the original /create-multipart
  request.
  
  Example:
  
  ```json
  "66e86218-80d9-4bda-b4d5-2b6def968705"
  ```

- `parts` (required)
  Type: array
  
  All of the part numbers and their corresponding ETags
  that have been uploaded must be provided.
  
  Example:
  
  ```json
  [
    {
      "part_number": 1,
      "etag": "0c376dcfcc2606f4335bbc732de93344"
    },
    {
      "part_number": 2,
      "etag": "09ert8cfcc2606f4335bbc732de91122"
    }
  ]
  ```

Additional properties: false

Responses:

- 200: external upload initialized

Content type: application/json

Type: any

- `id` (required)
  Type: integer

- `url` (required)
  Type: string

- `original_filename` (required)
  Type: string

- `filesize` (required)
  Type: integer

- `width` (required)
  Type: integer

- `height` (required)
  Type: integer

- `thumbnail_width` (required)
  Type: integer

- `thumbnail_height` (required)
  Type: integer

- `extension` (required)
  Type: string

- `short_url` (required)
  Type: string

- `short_path` (required)
  Type: string

- `retain_hours` (required)
  Type: string; nullable

- `human_filesize` (required)
  Type: string

- `dominant_color` (optional)
  Type: string; nullable

- `thumbnail` (optional)
  Type: object; nullable
  
  - `id` (optional)
    Type: integer
  
  - `upload_id` (optional)
    Type: integer
  
  - `url` (optional)
    Type: string
  
  - `extension` (optional)
    Type: string
  
  - `width` (optional)
    Type: integer
  
  - `height` (optional)
    Type: integer
  
  - `filesize` (optional)
    Type: integer
  
  Additional properties: false

- `optimized_video` (optional)
  Type: object; nullable
  
  - `id` (optional)
    Type: integer
  
  - `upload_id` (optional)
    Type: integer
  
  - `url` (optional)
    Type: string
  
  - `extension` (optional)
    Type: string
  
  - `filesize` (optional)
    Type: integer
  
  - `sha1` (optional)
    Type: string
  
  - `original_filename` (optional)
    Type: string
  
  Additional properties: false

Additional properties: false

## Examples

### cURL

```bash
curl -X POST 'https://discourse.example.com/uploads/complete-multipart.json' \
  -H 'Content-Type: application/json' \
  --data-raw '{
  "unique_identifier": "66e86218-80d9-4bda-b4d5-2b6def968705",
  "parts": [
    {
      "part_number": 1,
      "etag": "0c376dcfcc2606f4335bbc732de93344"
    },
    {
      "part_number": 2,
      "etag": "09ert8cfcc2606f4335bbc732de91122"
    }
  ]
}'
```

### JavaScript

```javascript
const body = `{
  "unique_identifier": "66e86218-80d9-4bda-b4d5-2b6def968705",
  "parts": [
    {
      "part_number": 1,
      "etag": "0c376dcfcc2606f4335bbc732de93344"
    },
    {
      "part_number": 2,
      "etag": "09ert8cfcc2606f4335bbc732de91122"
    }
  ]
}`;

const response = await fetch('https://discourse.example.com/uploads/complete-multipart.json', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
  },
  body,
});

const data = await response.text();
```

### Python

```python
import requests

body = '''{
  "unique_identifier": "66e86218-80d9-4bda-b4d5-2b6def968705",
  "parts": [
    {
      "part_number": 1,
      "etag": "0c376dcfcc2606f4335bbc732de93344"
    },
    {
      "part_number": 2,
      "etag": "09ert8cfcc2606f4335bbc732de91122"
    }
  ]
}'''

response = requests.post(
    'https://discourse.example.com/uploads/complete-multipart.json',
    data=body.encode('utf-8'),
    headers={
        'Content-Type': 'application/json',
    },
)
print(response.text)
```
