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

# Complete a chunked upload

> Seal a chunked upload with PATCH /v1/objects/chunked: the server assembles the parts it received into the final file, which then counts toward your quota.

<ParamField header="Authorization" type="string" placeholder="API Key" required>
  The API key for your account. You can find this in your [account settings](https://squarecloud.app/en/account/security).
</ParamField>

Chunked Complete assembles the parts sent with [Chunked Part](/en/blob-reference/endpoint/chunked-part) into the final file. The part list is read on the server, so you only send the `upload` token. Once it answers, the file is stored and counts against your quota. Requires the `blob:write` scope, or the upload token that opened the upload, and an active plan.

What happens on a refusal depends on the cause:

* **The upload is kept open** when the account has no active plan (`PERMISSION_DENIED`), is over its quota (`STORAGE_QUOTA_EXCEEDED`) or storage is unavailable (503). Fix the cause and call Complete again, without re-sending any part.
* **The upload is aborted** and its parts are discarded when the file is smaller than 512 bytes (`FILE_TOO_SMALL`) or larger than its limit (`FILE_TOO_LARGE`).
* **Nothing changes** when no part was sent yet (`NO_CHUNKS_UPLOADED`) or a part other than the last is under 5 MB (`CHUNK_TOO_SMALL`): re-send that part and complete again.

## Parameters

<ParamField body="upload" type="string" required>
  The `upload` token returned by Chunked Init. It can also go in the `upload` query parameter.
</ParamField>

## Rate limits

<Note>5 requests per 10 seconds, so several parallel uploads can finish together (`RATE_LIMITED`, 429).</Note>

## Response

<ResponseField name="status" type="string">
  "success" if successful, "error" if not.
</ResponseField>

<ResponseField name="response" type="object">
  <Expandable title="Toggle object">
    <ResponseField name="id" type="string">
      The id of the stored file.
    </ResponseField>

    <ResponseField name="private" type="boolean">
      Whether the file is private.
    </ResponseField>

    <ResponseField name="url" type="string | null">
      The public URL, or `null` for private files.
    </ResponseField>

    <ResponseField name="expires_at" type="ISO 8601">
      When the file will be deleted. Present only when it expires.
    </ResponseField>

    <ResponseField name="size" type="number">
      The size of the file, in bytes.
    </ResponseField>

    <ResponseField name="parts" type="number">
      How many parts were assembled.
    </ResponseField>
  </Expandable>
</ResponseField>

<RequestExample>
  ```bash cURL theme={"system"}
  curl --request PATCH \
    --url 'https://blob.squarecloud.app/v1/objects/chunked' \
    --header 'Authorization: YOUR_API_KEY' \
    --header 'Content-Type: application/json' \
    --data '{ "upload": "UPLOAD_TOKEN" }'
  ```

  ```javascript JavaScript theme={"system"}
  const response = await fetch('https://blob.squarecloud.app/v1/objects/chunked', {
    method: 'PATCH',
    headers: {
      Authorization: 'YOUR_API_KEY',
      'Content-Type': 'application/json',
    },
    body: JSON.stringify({ upload: uploadToken }),
  });
  ```
</RequestExample>

<ResponseExample>
  ```json theme={"system"}
  {
    "status": "success",
    "response": {
      "id": "prv/3155597145698959364/genomics/dataset_mugws5c0-3c59dc048e8850243be8079a5c74d079.fastq.gz",
      "private": true,
      "url": null,
      "size": 2147483648,
      "parts": 128
    }
  }
  ```
</ResponseExample>

## Errors

| Code | HTTP | When |
| - | - | - |
| `INVALID_UPLOAD_TOKEN` | 400 | The `upload` token is missing, malformed or not yours. |
| `NO_CHUNKS_UPLOADED` | 400 | No part was sent yet. |
| `CHUNK_TOO_SMALL` | 400 | A part other than the last has less than 5 MB. |
| `FILE_TOO_SMALL` | 400 | The file has less than 512 bytes. The upload is aborted. |
| `PERMISSION_DENIED` | 401 | The account has no active plan. The upload stays open. |
| `STORAGE_QUOTA_EXCEEDED` | 403 | The file would pass the included storage. The upload stays open. |
| `UPLOAD_NOT_FOUND` | 404 | The upload was completed, aborted or expired. |
| `FILE_TOO_LARGE` | 413 | The file passes its size limit. The upload is aborted. |
| `RATE_LIMITED` | 429 | More than 5 requests in 10 seconds. |
| `UPLOAD_FAILED` | 500 | The assembly failed. Retry. |
| `PRIVATE_STORAGE_UNAVAILABLE` / `PUBLIC_STORAGE_UNAVAILABLE` | 503 | Storage is temporarily unavailable. The upload stays open. |

## Related

* Blob SDK: [`blob.put()`](/en/sdks/blob/uploads) runs the whole chunked flow for files above 90 MiB


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