Skip to main content

put /<uuid>/file

Put element file

Behaves exactly like POST /<uuid>/file - the same Upload-Complete, Upload-Length, Content-Disposition and Repr-Digest headers select between a direct upload (201 Created) and a resumable upload (204 No Content with a Location header), verify upload integrity, and the same Upload-Limit rules apply to chunk sizes.

The only difference is that this endpoint does not require the element to be empty: if it already has a file attached, that file is replaced once the (possibly resumable) upload completes - including replacing it with a file of a different extension, e.g. overwriting a .jpg with a .txt. The old file is removed from storage as part of the replacement.

Because a replacement is destructive, this endpoint supports If-Match against the current file’s ETag, letting concurrent writers detect that the file changed since it was last read. POST has no such check, since it can only ever create a file, never overwrite one.

If a Repr-Digest (or Content-Digest) sent with the upload does not match the uploaded content, the request fails with 400 Bad Request and the existing file is left untouched - a failed replacement never leaves the element without a file, or with a partially-written one.

Request

Create file directly

curl -X PUT \
-H 'Authorization: Bearer secret-token:PIPeJGUt7c00ENn8a5uDlc' \
-H 'Content-Type: application/octet-stream' \
-H 'Content-Disposition: attachment; filename="report.pdf"' \
--data-binary @report.pdf \
https://api.example.com/7b80b203-2b82-40f5-accd-c7089fe6114e/file
import requests
url = "https://api.example.com/7b80b203-2b82-40f5-accd-c7089fe6114e/file"
payload = "@report.pdf"
headers = {
"Authorization": "Bearer secret-token:PIPeJGUt7c00ENn8a5uDlc",
"Content-Type": "application/octet-stream",
"Content-Disposition": "attachment; filename=\"report.pdf\""
}
response = requests.put(url, data=payload, headers=headers)
print(response.json())
const url = 'https://api.example.com/7b80b203-2b82-40f5-accd-c7089fe6114e/file';
const options = {
method: 'PUT',
headers: {
Authorization: 'Bearer secret-token:PIPeJGUt7c00ENn8a5uDlc',
'Content-Type': 'application/octet-stream',
'Content-Disposition': 'attachment; filename="report.pdf"'
},
body: '@report.pdf'
};
try {
const response = await fetch(url, options);
const data = await response.json();
console.log(data);
} catch (error) {
console.error(error);
}
<?php
$client = new \GuzzleHttp\Client();
$response = $client->request('PUT', 'https://api.example.com/7b80b203-2b82-40f5-accd-c7089fe6114e/file', [
'body' => '@report.pdf',
'headers' => [
'Authorization' => 'Bearer secret-token:PIPeJGUt7c00ENn8a5uDlc',
'Content-Disposition' => 'attachment; filename="report.pdf"',
'Content-Type' => 'application/octet-stream',
],
]);
echo $response->getBody();

Create resumable upload

curl -X PUT \
-H 'Authorization: Bearer secret-token:PIPeJGUt7c00ENn8a5uDlc' \
-H 'Content-Type: application/octet-stream' \
-H 'Content-Disposition: attachment; filename="report.pdf"' \
-H 'Upload-Complete: ?0' \
-H 'Upload-Length: 20971520' \
--data-binary @report.pdf.part1 \
https://api.example.com/7b80b203-2b82-40f5-accd-c7089fe6114e/file
import requests
url = "https://api.example.com/7b80b203-2b82-40f5-accd-c7089fe6114e/file"
payload = "@report.pdf.part1"
headers = {
"Authorization": "Bearer secret-token:PIPeJGUt7c00ENn8a5uDlc",
"Content-Type": "application/octet-stream",
"Content-Disposition": "attachment; filename=\"report.pdf\"",
"Upload-Complete": "?0",
"Upload-Length": "20971520"
}
response = requests.put(url, data=payload, headers=headers)
print(response.json())
const url = 'https://api.example.com/7b80b203-2b82-40f5-accd-c7089fe6114e/file';
const options = {
method: 'PUT',
headers: {
Authorization: 'Bearer secret-token:PIPeJGUt7c00ENn8a5uDlc',
'Content-Type': 'application/octet-stream',
'Content-Disposition': 'attachment; filename="report.pdf"',
'Upload-Complete': '?0',
'Upload-Length': '20971520'
},
body: '@report.pdf.part1'
};
try {
const response = await fetch(url, options);
const data = await response.json();
console.log(data);
} catch (error) {
console.error(error);
}
<?php
$client = new \GuzzleHttp\Client();
$response = $client->request('PUT', 'https://api.example.com/7b80b203-2b82-40f5-accd-c7089fe6114e/file', [
'body' => '@report.pdf.part1',
'headers' => [
'Authorization' => 'Bearer secret-token:PIPeJGUt7c00ENn8a5uDlc',
'Content-Disposition' => 'attachment; filename="report.pdf"',
'Content-Type' => 'application/octet-stream',
'Upload-Complete' => '?0',
'Upload-Length' => '20971520',
],
]);
echo $response->getBody();

Response

201 · Created

The complete file was uploaded directly (Upload-Complete: ?1, or the header was omitted) and is now attached to the element, replacing any previous file. Returned without a response body.

204 · No Content

A resumable upload (Upload-Complete: ?0) was created successfully. Its URL is returned in the Location header - continue it with PATCH, inspect it with HEAD, or abort it with DELETE against that URL.

400 · Bad Request

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

401 · Unauthorized

The provided token is either invalid or expired.

404 · Not Found

The referenced element does not exist.

412 · Precondition Failed

Precondition failed. If-Match or If-None-Match condition not met.

response has no body

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
X-Powered-By: Ember Nexus API

no schema available

response has no body

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
Location: /455a89b9-4ec7-4b02-b023-bcfbcbba9a9f
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

no schema available

{
"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>'."
}
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
X-Powered-By: Ember Nexus API
{
"$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"
}
}
}
{
"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)."
}
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
X-Powered-By: Ember Nexus API
{
"$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"
}
}
}
{
"type": "https://api.example.com/error/404/not-found",
"title": "Not Found",
"status": 404,
"detail": "Requested element was not found."
}
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
X-Powered-By: Ember Nexus API
{
"$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"
}
}
}
{
"type": "https://api.example.com/error/412/precondition-failed",
"title": "Precondition Failed",
"status": 412,
"detail": "Precondition does not match."
}
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
X-Powered-By: Ember Nexus API
{
"$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"
}
}
}

Request Parameters

uuid

required

pathstringuuid

Id of the element whose file is to be created or replaced.

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.

If-Match

optional

Used primarily for optimistic concurrency control — the request is only executed if the resource's ETag matches the provided value.

Upload-Complete

optional

?1 uploads the request body as the complete, final file. ?0 starts a resumable upload instead - the request body, if any, is stored as the first chunk. Omitting the header behaves like ?1.

Upload-Length

optional

Total size in bytes of the finished file. Only read when starting a resumable upload (Upload-Complete: ?0); optional even then.

Content-Disposition

optional

Original filename of the uploaded file, used to derive the file's extension. Falls back to bin if omitted or if no extension can be parsed.

Repr-Digest

optional

Cryptographic digest of the complete file, checked against the uploaded content once the direct upload finishes. Only sha-256 is supported. A mismatch fails with 400 Bad Request and the existing file (if any) is left untouched. Content-Digest is accepted as a fallback if Repr-Digest is absent. Only meaningful for a complete (non-resumable) upload; for a resumable upload, verify the digest on the completing PATCH request instead.

Request Body

no example available

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

Response Header

Location

always

URL of the newly created resource.

Upload-Complete

always

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

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.

Upload-Length

optional

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

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).

Expires

always

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

Access-Control-Allow-Headers

always

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

Access-Control-Allow-Methods

always

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

Access-Control-Allow-Origin

always

Specifies which origin(s) may access the resource.

Access-Control-Expose-Headers

always

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

Allow

always

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

Cache-Control

always

Directives controlling caching behavior for the response.

X-Powered-By

always

Identifies the underlying API implementation.