# Finish a large file upload

URL: https://clippie.ai/developers/docs/complete-file-upload

Finishes a multipart upload started with POST /v1/files/uploads and returns the file.

## At a glance

| Property | Value |
| --- | --- |
| REST | `POST https://api.clippie.ai/v1/files/uploads/complete` |
| MCP tool | REST only (not an MCP tool) |
| Scope | `create` |
| Cost | Spends nothing. Needs the `create` scope. |

## Parameters

| Name | In | Type | Required | Default | Description |
| --- | --- | --- | --- | --- | --- |
| `key` | body | string | Yes |  | 1-400 chars. |
| `uploadId` | body | string | Yes |  | 1-1000 chars. |
| `parts` | body | array of object | Yes |  | 1-10000 items. |

## Example

curl:

```bash
curl https://api.clippie.ai/v1/files/uploads/complete \
  -H "Authorization: Bearer $CLIPPIE_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "key": "KEY_FROM_CREATE_FILE_UPLOAD",
    "uploadId": "UPLOAD_ID_FROM_CREATE_FILE_UPLOAD",
    "parts": [
      {
        "partNumber": 1,
        "etag": "\"ETAG_FROM_THE_PART_UPLOAD\""
      }
    ]
  }'
```

complete-file-upload.mjs:

```js
const auth = { Authorization: `Bearer ${process.env.CLIPPIE_API_KEY}` };

const res = await fetch('https://api.clippie.ai/v1/files/uploads/complete', {
  method: 'POST',
  headers: { ...auth, 'Content-Type': 'application/json' },
  body: JSON.stringify({
    "key": "KEY_FROM_CREATE_FILE_UPLOAD",
    "uploadId": "UPLOAD_ID_FROM_CREATE_FILE_UPLOAD",
    "parts": [
      {
        "partNumber": 1,
        "etag": "\"ETAG_FROM_THE_PART_UPLOAD\""
      }
    ]
  }),
});
if (!res.ok) throw new Error((await res.json()).error.message);
console.log(await res.json());
```

## Response

`200` with JSON. The full response schema is in the [OpenAPI spec](https://api.clippie.ai/v1/openapi.json).
