API version: dev

---

# PATCH /upload/\<uuid> — Patch upload

Appends the next chunk to a resumable upload created by [`POST /<uuid>/file`](/api/post-element-file.md) or [`PUT /<uuid>/file`](/api/put-element-file.md).

Every request requires `Content-Type: application/partial-upload` and an `Upload-Offset` header equal to the upload's
current offset - the value from the previous response's `Upload-Offset` header (or `HEAD`'s, if reconnecting after a
restart). An offset that does not match fails with `409 Conflict`, listing the expected and provided values in the
problem's details, so the client can re-synchronize.

Set `Upload-Complete: ?1` on the chunk that finishes the upload. Its body may be empty - a zero-length chunk with
`Upload-Complete: ?1` is a valid way to complete an upload without transmitting further data, and behaves like
[`HEAD /upload/<uuid>`](/api/head-upload.md) otherwise, since zero-length chunks are always accepted regardless of the
configured minimum chunk size.

Once the final chunk is stored, all chunks are merged and attached as the target element's file (as if uploaded via
[`PUT /<uuid>/file`](/api/put-element-file.md)), and the resumable upload itself ceases to exist - subsequent requests against its
URL respond with `404`.

> **⚠ Note**
>
> Every unfinished upload has a limited lifetime, reported in the `max-age` field of its `Upload-Limit` header and
> reflected in its `Expires` header. Once that time passes, appending further chunks fails with `410 Gone`; the
> upload has to be recreated from scratch via `POST` or `PUT`.

> **⚠ Note**
>
> This endpoint does not support `If-Match` or `If-None-Match`; unlike the element endpoints, requesting it with
> either header has no effect.

On the chunk that sets `Upload-Complete: ?1`, a `Repr-Digest` header (or `Content-Digest`, as a fallback) can be sent
with the SHA-256 digest of the complete, reassembled file, in
[RFC 9530](https://datatracker.ietf.org/doc/html/rfc9530) structured-field format (`sha-256=:[base64]:`), the same as
for a direct upload on [`POST /<uuid>/file`](/api/post-element-file.md). A mismatch fails with `400 Bad Request`; the
uploaded chunks are discarded and the upload's target element keeps whatever file it had before (if any).

## Request

```bash
curl -X PATCH \
  -H 'Authorization: Bearer secret-token:PIPeJGUt7c00ENn8a5uDlc' \
  -H 'Content-Type: application/partial-upload' \
  -H 'Upload-Complete: ?1' \
  -H 'Upload-Offset: 5242880' \
  -d '<binary chunk data>' \
  https://api.example.com/upload/7b80b203-2b82-40f5-accd-c7089fe6114e
```

## Response

### 204 · No Content

The chunk was stored successfully.\
Specific meaning depends on `Upload-Complete`:

- `?0`: The chunk was appended, and the upload remains open for further chunks. Its new state is returned in the response headers.
- `?1`: The chunk was appended and the upload is now complete - the uploaded chunks were merged and attached as the target element's file, and the resumable upload no longer exists.

#### Headers

```http
Access-Control-Allow-Headers: Authorization, Origin, X-Requested-With, Content-Type, Accept, Access-Control-Request-Method
Access-Control-Allow-Methods: GET, HEAD, POST, OPTIONS, PUT, PATCH, DELETE, PROPFIND, PROPPATCH, MKCOL, COPY, MOVE, LOCK, UNLOCK
Access-Control-Allow-Origin: *
Access-Control-Expose-Headers: ETag, Location
Allow: GET, HEAD, POST, OPTIONS, PUT, PATCH, DELETE, PROPFIND, PROPPATCH, MKCOL, COPY, MOVE, LOCK, UNLOCK
Cache-Control: no-cache, private
Upload-Complete: ?0
Upload-Offset: 5242880
Upload-Length: 20971520
Upload-Limit: max-age=10800, max-size=10737418240, min-append-size=5242880, max-append-size=105906176
Expires: Sat, 22 Aug 2026 21:22:07 GMT
X-Powered-By: Ember Nexus API
```

[MDN](https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Status/204) · [HTTP.dev](https://http.dev/204)

### 400 · Bad Request

A provided property has the wrong type or fails a validation rule.

#### Body

```json
{
  "type": "https://api.example.com/error/400/bad-content",
  "title": "Bad content",
  "status": 400,
  "detail": "Endpoint expects property 'newPassword' to be password which is not identical to the old password, got string '<redacted>'."
}
```

#### Headers

`Access-Control-Allow-Headers`, `Access-Control-Allow-Methods`, `Access-Control-Allow-Origin`, `Access-Control-Expose-Headers`, `Allow`, `Cache-Control`, `X-Powered-By`. Descriptions and example values are in the Response Header section below.

#### Schema

Same as `Problem` — see the Response Schema section below.

[MDN](https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Status/400) · [HTTP.dev](https://http.dev/400)

### 401 · Unauthorized

The provided token is either invalid or expired.

#### Body

```json
{
  "type": "https://api.example.com/error/401/unauthorized",
  "title": "Unauthorized",
  "status": 401,
  "detail": "Authorization for the request failed due to possible problems with the token (incorrect or expired), password (incorrect or changed), the user's unique identifier, or the user's status (e.g., missing, blocked, or deleted)."
}
```

#### Headers

`Access-Control-Allow-Headers`, `Access-Control-Allow-Methods`, `Access-Control-Allow-Origin`, `Access-Control-Expose-Headers`, `Allow`, `Cache-Control`, `X-Powered-By`. Descriptions and example values are in the Response Header section below.

#### Schema

Same as `Problem` — see the Response Schema section below.

[MDN](https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Status/401) · [HTTP.dev](https://http.dev/401)

### 404 · Not Found

No resumable upload with this id exists, it already completed, it belongs to a different user, or the current user has since lost `UPDATE` access to the upload's target element.

#### Body

```json
{
  "type": "https://api.example.com/error/404/not-found",
  "title": "Not Found",
  "status": 404,
  "detail": "Requested element was not found."
}
```

#### Headers

`Access-Control-Allow-Headers`, `Access-Control-Allow-Methods`, `Access-Control-Allow-Origin`, `Access-Control-Expose-Headers`, `Allow`, `Cache-Control`, `X-Powered-By`. Descriptions and example values are in the Response Header section below.

#### Schema

Same as `Problem` — see the Response Schema section below.

[MDN](https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Status/404) · [HTTP.dev](https://http.dev/404)

### 409 · Conflict

The `Upload-Offset` in the request does not match the upload's current offset, or the appended chunk would exceed the upload's declared `Upload-Length`.

#### Body

```json
{
  "type": "https://api.example.com/error/409/conflict",
  "title": "Conflict",
  "status": 409,
  "detail": "Offset from request does not match offset of resource.",
  "expected-offset": 20971520,
  "provided-offset": 10485760
}
```

#### Headers

`Access-Control-Allow-Headers`, `Access-Control-Allow-Methods`, `Access-Control-Allow-Origin`, `Access-Control-Expose-Headers`, `Allow`, `Cache-Control`, `X-Powered-By`. Descriptions and example values are in the Response Header section below.

#### Schema

Same as `Problem` — see the Response Schema section below.

[MDN](https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Status/409) · [HTTP.dev](https://http.dev/409)

### 410 · Gone

The upload has expired and its data has already been discarded.

#### Body

```json
{
  "type": "https://api.example.com/error/410/gone",
  "title": "Gone",
  "status": 410,
  "detail": "Requested resource is no longer available and is expected to soon be permanently deleted."
}
```

#### Headers

`Access-Control-Allow-Headers`, `Access-Control-Allow-Methods`, `Access-Control-Allow-Origin`, `Access-Control-Expose-Headers`, `Allow`, `Cache-Control`, `X-Powered-By`. Descriptions and example values are in the Response Header section below.

#### Schema

Same as `Problem` — see the Response Schema section below.

[MDN](https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Status/410) · [HTTP.dev](https://http.dev/410)

## Request Parameters

### `uuid` (required)

`path · string · uuid`

Id of the resumable upload, as returned in the `Location` header of the request that created it.

## Request Header

### `Authorization` (optional)

Bearer token for user authentication. If omitted, the request is processed as an anonymous user; if provided, the associated user account is used.

[MDN](https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/Authorization) · [HTTP.dev](https://http.dev/authorization) · [Authentication guide](/guide/authentication.md)

### `Upload-Offset` (required)

Byte offset the appended chunk starts at. Must match the upload's current `Upload-Offset` exactly, otherwise the request fails with `409 Conflict`.

### `Upload-Complete` (optional)

`?1` marks this as the final chunk, completing the upload; omitted or `?0` keeps the upload open for further chunks.

### `Repr-Digest` (optional)

Cryptographic digest of the complete (reassembled) file. Only read on the chunk that sets `Upload-Complete: ?1`, and checked against the merged file once assembled. Only `sha-256` is supported. A mismatch fails with `400 Bad Request`; the uploaded chunks are discarded and the upload's target element keeps its previous file, if any. `Content-Digest` is accepted as a fallback if `Repr-Digest` is absent.

## Request Body (optional)

#### Schema

```json
{
  "type": "string",
  "format": "binary"
}
```

## Response Schema

### `Problem`

RFC 7807 Problem Details object.

```json
{
  "$schema": "https://spec.openapis.org/oas/3.0/schema/2021-09-28#/definitions/Schema",
  "type": "object",
  "description": "RFC 7807 Problem Details object.",
  "properties": {
    "type": {
      "type": "string",
      "format": "uri"
    },
    "title": {
      "type": "string"
    },
    "status": {
      "type": "integer"
    },
    "detail": {
      "type": "string"
    }
  }
}
```

## Response Header

### `Upload-Complete` (always)

Structured boolean indicating whether the upload is finished: `?1` for complete, `?0` for still in progress.

Example: `?0`

[IETF draft](https://datatracker.ietf.org/doc/draft-ietf-httpbis-resumable-upload/) · [HTTP.dev](https://http.dev/upload-complete)

### `Upload-Offset` (always)

Number of bytes already stored for the resumable upload. On a request, it must match the upload's current offset exactly; on a response, it reflects the offset after the request was processed.

Example: `5242880`

[IETF draft](https://datatracker.ietf.org/doc/draft-ietf-httpbis-resumable-upload/) · [HTTP.dev](https://http.dev/upload-offset)

### `Upload-Length` (optional)

Total number of bytes the finished file will have. Optional - omitted when the total size is not known ahead of time.

Example: `20971520`

[IETF draft](https://datatracker.ietf.org/doc/draft-ietf-httpbis-resumable-upload/) · [HTTP.dev](https://http.dev/upload-length)

### `Upload-Limit` (always)

Structured field listing the server's limits for this upload: `max-age` (seconds an unfinished upload is kept alive since its first request), `max-size` (maximum total file size in bytes), `min-append-size` (minimum size in bytes for a non-final chunk) and `max-append-size` (maximum size in bytes per chunk).

Example: `max-age=10800, max-size=10737418240, min-append-size=5242880, max-append-size=105906176`

[IETF draft](https://datatracker.ietf.org/doc/draft-ietf-httpbis-resumable-upload/) · [HTTP.dev](https://http.dev/upload-limit)

### `Expires` (always)

Point in time after which the unfinished resumable upload is discarded, if it is not completed before then.

Example: `Sat, 22 Aug 2026 21:22:07 GMT`

[MDN](https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/Expires) · [HTTP.dev](https://http.dev/expires)

### Other Headers

#### `Access-Control-Allow-Headers` (always)

Specifies which HTTP headers can be used during a cross-origin request, returned in preflight responses.

Example: `Authorization, Origin, X-Requested-With, Content-Type, Accept, Access-Control-Request-Method`

[MDN](https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/Access-Control-Allow-Headers) · [HTTP.dev](https://http.dev/access-control-allow-headers)

#### `Access-Control-Allow-Methods` (always)

Indicates which HTTP methods are permitted for cross-origin requests, typically returned in preflight responses.

Example: `GET, HEAD, POST, OPTIONS, PUT, PATCH, DELETE, PROPFIND, PROPPATCH, MKCOL, COPY, MOVE, LOCK, UNLOCK`

[MDN](https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/Access-Control-Allow-Methods) · [HTTP.dev](https://http.dev/access-control-allow-methods)

#### `Access-Control-Allow-Origin` (always)

Specifies which origin(s) may access the resource.

Example: `*`

[MDN](https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/Access-Control-Allow-Origin) · [HTTP.dev](https://http.dev/access-control-allow-origin)

#### `Access-Control-Expose-Headers` (always)

Lists the response headers that browsers are allowed to access from JavaScript beyond the default restricted set.

Example: `ETag, Location`

[MDN](https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/Access-Control-Expose-Headers) · [HTTP.dev](https://http.dev/access-control-expose-headers)

#### `Allow` (always)

Lists the HTTP methods supported by the endpoint; returned alongside a `405 Method Not Allowed` response.

Example: `GET, HEAD, POST, OPTIONS, PUT, PATCH, DELETE, PROPFIND, PROPPATCH, MKCOL, COPY, MOVE, LOCK, UNLOCK`

[MDN](https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/Allow) · [HTTP.dev](https://http.dev/allow)

#### `Cache-Control` (always)

Directives controlling caching behavior for the response.

Example: `no-cache, private`

[MDN](https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/Cache-Control) · [HTTP.dev](https://http.dev/cache-control)

#### `X-Powered-By` (always)

Identifies the underlying API implementation.

Example: `Ember Nexus API`

[MDN](https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/X-Powered-By) · [HTTP.dev](https://http.dev/x-powered-by)

---

Home: [Ember Nexus API docs](/index.md)

Full site map: [llms.txt](/llms.txt)

Previous: [Head upload](/api/head-upload.md)

Next: [Delete upload](/api/delete-upload.md)
