Copy or Move a Blob Object
curl --request POST \
--url https://blob.vertracloud.app/v1/objects/copy \
--header 'Content-Type: application/json' \
--data '
{
"source": "<string>",
"path": "<string>",
"move": true,
"overwrite": true,
"random_suffix": true,
"rename_on_conflict": true,
"visibility": "<string>"
}
'import requests
url = "https://blob.vertracloud.app/v1/objects/copy"
payload = {
"source": "<string>",
"path": "<string>",
"move": True,
"overwrite": True,
"random_suffix": True,
"rename_on_conflict": True,
"visibility": "<string>"
}
headers = {"Content-Type": "application/json"}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {'Content-Type': 'application/json'},
body: JSON.stringify({
source: '<string>',
path: '<string>',
move: true,
overwrite: true,
random_suffix: true,
rename_on_conflict: true,
visibility: '<string>'
})
};
fetch('https://blob.vertracloud.app/v1/objects/copy', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://blob.vertracloud.app/v1/objects/copy",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'source' => '<string>',
'path' => '<string>',
'move' => true,
'overwrite' => true,
'random_suffix' => true,
'rename_on_conflict' => true,
'visibility' => '<string>'
]),
CURLOPT_HTTPHEADER => [
"Content-Type: application/json"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://blob.vertracloud.app/v1/objects/copy"
payload := strings.NewReader("{\n \"source\": \"<string>\",\n \"path\": \"<string>\",\n \"move\": true,\n \"overwrite\": true,\n \"random_suffix\": true,\n \"rename_on_conflict\": true,\n \"visibility\": \"<string>\"\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://blob.vertracloud.app/v1/objects/copy")
.header("Content-Type", "application/json")
.body("{\n \"source\": \"<string>\",\n \"path\": \"<string>\",\n \"move\": true,\n \"overwrite\": true,\n \"random_suffix\": true,\n \"rename_on_conflict\": true,\n \"visibility\": \"<string>\"\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://blob.vertracloud.app/v1/objects/copy")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Content-Type"] = 'application/json'
request.body = "{\n \"source\": \"<string>\",\n \"path\": \"<string>\",\n \"move\": true,\n \"overwrite\": true,\n \"random_suffix\": true,\n \"rename_on_conflict\": true,\n \"visibility\": \"<string>\"\n}"
response = http.request(request)
puts response.read_body{
"response": {
"id": "0b6f7c1e-3d2a-4f5b-9a8c-1d2e3f4a5b6c",
"path": "images/logo.png",
"size": 48213,
"content_type": "image/png",
"etag": "9b2cf535f27731c974343645a3085d39",
"sha256": null,
"visibility": "public",
"url": "https://blob.vertracloud.dev/k7p2m9x4qa/images/logo.png",
"cache_control": null,
"content_disposition": "inline",
"filename": null,
"metadata": {},
"expires_at": null,
"created_at": "2026-10-14T12:00:00.000Z",
"updated_at": "2026-10-14T12:00:00.000Z"
}
}
Objects
Copy or Move a Blob Object
Copies a blob object to a new path, or moves it. A move keeps the object ID; a copy creates a new object that counts toward storage.
POST
/
v1
/
objects
/
copy
Copy or Move a Blob Object
curl --request POST \
--url https://blob.vertracloud.app/v1/objects/copy \
--header 'Content-Type: application/json' \
--data '
{
"source": "<string>",
"path": "<string>",
"move": true,
"overwrite": true,
"random_suffix": true,
"rename_on_conflict": true,
"visibility": "<string>"
}
'import requests
url = "https://blob.vertracloud.app/v1/objects/copy"
payload = {
"source": "<string>",
"path": "<string>",
"move": True,
"overwrite": True,
"random_suffix": True,
"rename_on_conflict": True,
"visibility": "<string>"
}
headers = {"Content-Type": "application/json"}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {'Content-Type': 'application/json'},
body: JSON.stringify({
source: '<string>',
path: '<string>',
move: true,
overwrite: true,
random_suffix: true,
rename_on_conflict: true,
visibility: '<string>'
})
};
fetch('https://blob.vertracloud.app/v1/objects/copy', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://blob.vertracloud.app/v1/objects/copy",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'source' => '<string>',
'path' => '<string>',
'move' => true,
'overwrite' => true,
'random_suffix' => true,
'rename_on_conflict' => true,
'visibility' => '<string>'
]),
CURLOPT_HTTPHEADER => [
"Content-Type: application/json"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://blob.vertracloud.app/v1/objects/copy"
payload := strings.NewReader("{\n \"source\": \"<string>\",\n \"path\": \"<string>\",\n \"move\": true,\n \"overwrite\": true,\n \"random_suffix\": true,\n \"rename_on_conflict\": true,\n \"visibility\": \"<string>\"\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://blob.vertracloud.app/v1/objects/copy")
.header("Content-Type", "application/json")
.body("{\n \"source\": \"<string>\",\n \"path\": \"<string>\",\n \"move\": true,\n \"overwrite\": true,\n \"random_suffix\": true,\n \"rename_on_conflict\": true,\n \"visibility\": \"<string>\"\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://blob.vertracloud.app/v1/objects/copy")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Content-Type"] = 'application/json'
request.body = "{\n \"source\": \"<string>\",\n \"path\": \"<string>\",\n \"move\": true,\n \"overwrite\": true,\n \"random_suffix\": true,\n \"rename_on_conflict\": true,\n \"visibility\": \"<string>\"\n}"
response = http.request(request)
puts response.read_body{
"response": {
"id": "0b6f7c1e-3d2a-4f5b-9a8c-1d2e3f4a5b6c",
"path": "images/logo.png",
"size": 48213,
"content_type": "image/png",
"etag": "9b2cf535f27731c974343645a3085d39",
"sha256": null,
"visibility": "public",
"url": "https://blob.vertracloud.dev/k7p2m9x4qa/images/logo.png",
"cache_control": null,
"content_disposition": "inline",
"filename": null,
"metadata": {},
"expires_at": null,
"created_at": "2026-10-14T12:00:00.000Z",
"updated_at": "2026-10-14T12:00:00.000Z"
}
}
Copies a blob object to a new
path in the same account, or moves it when move is true. A move keeps the object id and changes only path, so it doesn’t add to storage. A copy creates a new object with a new id, and its bytes count toward the quota.
Scope: blob:write.
string
required
ID of the object to copy or move.
string
required
Destination path, with the same rules as Upload in one request.
boolean
true moves the object and keeps its ID. Default false: copy.boolean
Replace an object already at
path. Default false.boolean
Insert a random suffix before the extension. Default
false.boolean
Copy only: when
path is taken, including by the source itself, save the copy as name-1.ext, name-2.ext and so on instead of returning BLOB_OBJECT_ALREADY_EXISTS. Default false. Can’t be combined with overwrite, and is ignored on a move.string
public or private for the new object. Default: the visibility of the source object.string
The workspace ID, when the blob belongs to a workspace. The call acts on the blob of the workspace owner and needs the
blob:read workspace permission (blob:manage on routes that change data). Leave it out to act on your own blob.Example request
curl -X POST "https://blob.vertracloud.app/v1/objects/copy" \
-H "Authorization: Bearer $VERTRA_API_KEY" \
-H "Content-Type: application/json" \
-d '{"source":"0b6f7c1e-3d2a-4f5b-9a8c-1d2e3f4a5b6c","path":"backup/logo.png"}'
Response
object
The object at its new path.
Show properties
Show properties
string
Stable ID of the object. It never changes, even when the path, visibility or expiration does.
string
Full path inside the account, for example
images/avatars/joao.png.number
Size in bytes.
string
MIME type, derived on the server from the file extension.
string
Entity tag of the stored content.
string | null
SHA-256 of the content in hex, when the upload sent a checksum.
null otherwise.string
public (readable through its public URL) or private (needs a temporary link or a share).string | null
Public URL.
null while the object is private.string | null
immutable, max-age=<seconds> or no-cache (no-cache needs Enterprise-26 or higher). null means the default.string
inline (shown by the browser) or attachment (downloaded). HTML, SVG and XML are always attachment.string | null
Name suggested on download.
null uses the last segment of path.object
Up to 5 keys, each
[a-z0-9-]{1,64}, 512 bytes in total. Enterprise-12 or higher; {} on other plans.string | null
When the object is deleted, as an ISO 8601 timestamp.
null means no expiration.string
ISO 8601 creation time.
string
ISO 8601 time of the last change.
{
"response": {
"id": "0b6f7c1e-3d2a-4f5b-9a8c-1d2e3f4a5b6c",
"path": "images/logo.png",
"size": 48213,
"content_type": "image/png",
"etag": "9b2cf535f27731c974343645a3085d39",
"sha256": null,
"visibility": "public",
"url": "https://blob.vertracloud.dev/k7p2m9x4qa/images/logo.png",
"cache_control": null,
"content_disposition": "inline",
"filename": null,
"metadata": {},
"expires_at": null,
"created_at": "2026-10-14T12:00:00.000Z",
"updated_at": "2026-10-14T12:00:00.000Z"
}
}
Error Responses
string
The error code indicating the reason for failure. Possible values:
AUTH_TOKEN_MISSING(401): NoAuthorizationheader was sent.API_KEY_INVALID(401): The API key doesn’t exist, was revoked, or its secret doesn’t match.API_KEY_SCOPE_DENIED(403): The key lacks the scope this route needs (blob:readorblob:write);details.requirednames it.WORKSPACE_PERMISSION_DENIED(403): Only withworkspace_id: you’re not a member, or your role lacks the blob permission.WORKSPACE_NOT_FOUND(404): Only withworkspace_id: no workspace with that ID, or you’re not a member.BLOB_NAMESPACE_SUSPENDED(403): The account’s blob storage is suspended, or its plan expired. Uploads and other writes are refused from the start of the 72-hour grace period.VALIDATION_ERROR(400): A parameter or body field failed validation.details.pathnames the field.BLOB_OBJECT_NOT_FOUND(404): Thesourcedoesn’t exist in this account.BLOB_OBJECT_ALREADY_EXISTS(409):pathis taken andoverwriteis nottrue.STORAGE_QUOTA_EXCEEDED(403): A copy would exceed the plan’s blob quota. Moves don’t add storage, so they’re not blocked by it.BLOCKED_FILE_TYPE(422): The destination extension is blocked or not allowed by the folder rule.
{
"code": "AUTH_TOKEN_MISSING"
}
{
"code": "API_KEY_SCOPE_DENIED"
}
{
"code": "WORKSPACE_NOT_FOUND"
}
{
"code": "VALIDATION_ERROR"
}
{
"code": "BLOB_OBJECT_ALREADY_EXISTS"
}
{
"code": "BLOCKED_FILE_TYPE"
}