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

# Complete Upload

> Turn an uploaded file into a Wordsmith file with a file_id.

> [!NOTE]
>
> **Preview.** This endpoint is available to organisations in the Wordsmith MCP and files pilot. Other organisations receive `403 mcp_not_enabled`. See the [preview overview](/preview).

Turns an upload into a file and returns it. The response's `id` is the file's `file_id`, which the other files endpoints and [Attach Files](/api-reference/tasks/attach-files) take.

An upload takes three calls:

1. Call [Upload URL](/api-reference/files/upload-url). It returns `upload_url` and `job_id`.
2. `PUT` the file's bytes to `upload_url`, with a `Content-Type` header equal to the `content_type` you sent.
3. Call this endpoint with the `job_id` as `upload_id`.

The file lands in your private space. Only the user who created the upload can complete it, and only while they may still upload files.

Completing is safe to retry. Completing the same upload again returns the same file, for up to an hour. Two concurrent requests also get the same file: the second waits up to 10 seconds for the first to finish. If the first is still running after that, the second gets `409 upload_completion_in_progress`; retry it.

If Wordsmith has not received the bytes yet, the response is `400 upload_not_received` and the upload stays open. `PUT` the bytes, then complete again.

An upload is used once. After you complete it, attach the file by its `file_id`, not the `job_id`. A `job_id` already used as an `upload_job_id` attachment cannot be completed.

## Authentication

Send an API key, or an OAuth access token with the `files:write` scope, as a bearer token in the `Authorization` header. A token without the scope gets `403` with `"error": "insufficient_scope"`.

## Path parameters

**upload\_id** `string (uuid)` *required*

The `job_id` that [Upload URL](/api-reference/files/upload-url) returned.

## Response

Returns `200` with the file.

**id** `string (uuid)`

The file's id: the `file_id` other endpoints take.

**file\_name** `string | null`

The file's name.

**content\_type** `string | null`

The file's MIME type.

**content\_length** `integer | null`

Size in bytes.

**created\_at** `string | null`

When the file was created. ISO 8601 UTC.

```bash cURL theme={null}
# Step 1: get an upload URL
curl -X POST "https://api.wordsmith.ai/api/v1/files/upload-url" \
  -H "Authorization: Bearer sk-ws-api1-your_api_key_here" \
  -H "Content-Type: application/json" \
  -d '{"file_name": "contract.pdf", "content_type": "application/pdf"}'

# Step 2: PUT the bytes to upload_url
curl -X PUT "UPLOAD_URL_FROM_STEP_1" \
  -H "Content-Type: application/pdf" \
  --data-binary @contract.pdf

# Step 3: complete the upload with job_id
curl -X POST "https://api.wordsmith.ai/api/v1/files/uploads/4b7f2e91-6c3a-4d58-a0e2-9f1c8b5d3a76/complete" \
  -H "Authorization: Bearer sk-ws-api1-your_api_key_here"
```

```json Response theme={null}
{
  "id": "7c3e9a51-2d84-4f06-b1c7-5e9d0a2f8b63",
  "file_name": "contract.pdf",
  "content_type": "application/pdf",
  "content_length": 482113,
  "created_at": "2026-10-13T09:14:22.512000Z"
}
```

## Errors

See [Errors](/errors) for the error format.

| HTTP Status | Error Code | When |
| - | - | - |
| 400 | `invalid_upload_job` | The upload does not exist, has expired, was already used, or belongs to another user. Create a new upload and send the file again. |
| 400 | `upload_not_received` | Wordsmith has not received the file's bytes. `PUT` them to `upload_url`, then complete again. |
| 400 | `upload_too_large` | The uploaded file is over its size limit. `size_limit_bytes` gives the limit. |
| 401 | `unauthorized` | The API key is missing or invalid. |
| 403 | `forbidden` | Your user may no longer upload files. |
| 403 | `mcp_not_enabled` | Your organisation is not in the preview. |
| 409 | `upload_completion_in_progress` | Another request is completing this upload. Retry shortly. |


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