API reference
Library
Workspace-level media storage. Upload files once and reuse them across projects, list and tag what you have stored, and use chunked uploads for large files.
#List workspace Library assets
One page of the workspace's shared Library, newest first. Each item carries a presigned GET URL that expires: never persist it.
https://api.rendley.com/v1/workspaces/{workspaceId}/libraryDon't have one? Create an API key
const res = await fetch("https://api.rendley.com/v1/workspaces/WORKSPACE_ID/library", {
headers: { Authorization: "Bearer YOUR_API_KEY" },
});
const { data } = await res.json();curl "https://api.rendley.com/v1/workspaces/WORKSPACE_ID/library" \
-H "Authorization: Bearer YOUR_API_KEY"import requests
res = requests.get(
"https://api.rendley.com/v1/workspaces/WORKSPACE_ID/library",
headers={"Authorization": "Bearer YOUR_API_KEY"},
)
data = res.json()["data"]$ch = curl_init("https://api.rendley.com/v1/workspaces/WORKSPACE_ID/library");
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, ["Authorization: Bearer YOUR_API_KEY"]);
$response = curl_exec($ch);
curl_close($ch);
$data = json_decode($response, true)["data"];package main
import (
"fmt"
"io"
"net/http"
)
func main() {
req, _ := http.NewRequest("GET", "https://api.rendley.com/v1/workspaces/WORKSPACE_ID/library", nil)
req.Header.Set("Authorization", "Bearer YOUR_API_KEY")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
b, _ := io.ReadAll(res.Body)
fmt.Println(string(b))
}require "net/http"
require "json"
uri = URI("https://api.rendley.com/v1/workspaces/WORKSPACE_ID/library")
req = Net::HTTP::Get.new(uri)
req["Authorization"] = "Bearer YOUR_API_KEY"
res = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) { |http| http.request(req) }
data = JSON.parse(res.body)["data"]Response 200
{
"data": {
"items": [
{
"created_at": "string",
"deduplicated": true,
"download_url": "string",
"duration": 0,
"file_hash": "c6c8ec4f9a6fdd9d",
"file_size": 0,
"id": "3f0d5a4e-3d2a-4c1f-9b3e-2a1c4d5e6f70",
"media_id": "c448b6e3-2b78-4bda-b369-d1afc6aec07f",
"mime_type": "string",
"original_file_name": "string",
"source": "string",
"tags": [
"string"
],
"thumbnail_url": "string",
"url": "string",
"workspace_id": "3f0d5a4e-3d2a-4c1f-9b3e-2a1c4d5e6f70"
}
],
"limit": 0,
"offset": 0,
"total": 0
}
}#Upload a file into the workspace Library (proxy transport)
https://api.rendley.com/v1/workspaces/{workspaceId}/librarySingle-call upload: stream the raw file bytes as the request body. The server hashes while storing and returns the completed asset: no separate complete step. Metadata travels in query params. Content-Length is required; files above the proxy cap must use the multipart flow. If identical content already exists in the Library the existing asset is returned with deduplicated=true.
Don't have one? Create an API key
const res = await fetch("https://api.rendley.com/v1/workspaces/WORKSPACE_ID/library", {
method: "POST",
headers: { Authorization: "Bearer YOUR_API_KEY" },
});
const { data } = await res.json();curl -X POST "https://api.rendley.com/v1/workspaces/WORKSPACE_ID/library" \
-H "Authorization: Bearer YOUR_API_KEY"import requests
res = requests.post(
"https://api.rendley.com/v1/workspaces/WORKSPACE_ID/library",
headers={"Authorization": "Bearer YOUR_API_KEY"},
)
data = res.json()["data"]$ch = curl_init("https://api.rendley.com/v1/workspaces/WORKSPACE_ID/library");
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "POST");
curl_setopt($ch, CURLOPT_HTTPHEADER, ["Authorization: Bearer YOUR_API_KEY"]);
$response = curl_exec($ch);
curl_close($ch);
$data = json_decode($response, true)["data"];package main
import (
"fmt"
"io"
"net/http"
)
func main() {
req, _ := http.NewRequest("POST", "https://api.rendley.com/v1/workspaces/WORKSPACE_ID/library", nil)
req.Header.Set("Authorization", "Bearer YOUR_API_KEY")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
b, _ := io.ReadAll(res.Body)
fmt.Println(string(b))
}require "net/http"
require "json"
uri = URI("https://api.rendley.com/v1/workspaces/WORKSPACE_ID/library")
req = Net::HTTP::Post.new(uri)
req["Authorization"] = "Bearer YOUR_API_KEY"
res = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) { |http| http.request(req) }
data = JSON.parse(res.body)["data"]Response 200
{
"data": {
"created_at": "string",
"deduplicated": true,
"download_url": "string",
"duration": 0,
"file_hash": "c6c8ec4f9a6fdd9d",
"file_size": 0,
"id": "3f0d5a4e-3d2a-4c1f-9b3e-2a1c4d5e6f70",
"media_id": "c448b6e3-2b78-4bda-b369-d1afc6aec07f",
"mime_type": "string",
"original_file_name": "string",
"source": "string",
"tags": [
"string"
],
"thumbnail_url": "string",
"url": "string",
"workspace_id": "3f0d5a4e-3d2a-4c1f-9b3e-2a1c4d5e6f70"
}
}#Rename a workspace Library asset
Update the asset's display name.
https://api.rendley.com/v1/workspaces/{workspaceId}/library/{uploadId}Don't have one? Create an API key
UploadID is read from the {uploadId} path segment on the public routes; the editor's flat mount still sends it in the body.
const res = await fetch("https://api.rendley.com/v1/workspaces/WORKSPACE_ID/library/UPLOAD_ID", {
method: "PATCH",
headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json" },
body: JSON.stringify({
"name": "<name>"
}),
});
const { data } = await res.json();curl -X PATCH "https://api.rendley.com/v1/workspaces/WORKSPACE_ID/library/UPLOAD_ID" \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"name": "<name>"
}'import requests
res = requests.patch(
"https://api.rendley.com/v1/workspaces/WORKSPACE_ID/library/UPLOAD_ID",
headers={"Authorization": "Bearer YOUR_API_KEY"},
json={
"name": "<name>"
},
)
data = res.json()["data"]$ch = curl_init("https://api.rendley.com/v1/workspaces/WORKSPACE_ID/library/UPLOAD_ID");
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "PATCH");
curl_setopt($ch, CURLOPT_HTTPHEADER, ["Authorization: Bearer YOUR_API_KEY", "Content-Type: application/json"]);
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode(["name" => "<name>"]));
$response = curl_exec($ch);
curl_close($ch);
$data = json_decode($response, true)["data"];package main
import (
"fmt"
"io"
"net/http"
"bytes"
)
func main() {
body := bytes.NewBufferString(`{
"name": "<name>"
}`)
req, _ := http.NewRequest("PATCH", "https://api.rendley.com/v1/workspaces/WORKSPACE_ID/library/UPLOAD_ID", body)
req.Header.Set("Authorization", "Bearer YOUR_API_KEY")
req.Header.Set("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
b, _ := io.ReadAll(res.Body)
fmt.Println(string(b))
}require "net/http"
require "json"
uri = URI("https://api.rendley.com/v1/workspaces/WORKSPACE_ID/library/UPLOAD_ID")
req = Net::HTTP::Patch.new(uri)
req["Authorization"] = "Bearer YOUR_API_KEY"
req["Content-Type"] = "application/json"
req.body = { name: "<name>" }.to_json
res = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) { |http| http.request(req) }
data = JSON.parse(res.body)["data"]Response 200
{
"data": {
"created_at": "string",
"deduplicated": true,
"download_url": "string",
"duration": 0,
"file_hash": "c6c8ec4f9a6fdd9d",
"file_size": 0,
"id": "3f0d5a4e-3d2a-4c1f-9b3e-2a1c4d5e6f70",
"media_id": "c448b6e3-2b78-4bda-b369-d1afc6aec07f",
"mime_type": "string",
"original_file_name": "string",
"source": "string",
"tags": [
"string"
],
"thumbnail_url": "string",
"url": "string",
"workspace_id": "3f0d5a4e-3d2a-4c1f-9b3e-2a1c4d5e6f70"
}
}#Delete a workspace Library asset
Remove the asset and refund its storage. Does not touch any project copies bridged from it.
https://api.rendley.com/v1/workspaces/{workspaceId}/library/{uploadId}Don't have one? Create an API key
const res = await fetch("https://api.rendley.com/v1/workspaces/WORKSPACE_ID/library/UPLOAD_ID", {
method: "DELETE",
headers: { Authorization: "Bearer YOUR_API_KEY" },
});
const { data } = await res.json();curl -X DELETE "https://api.rendley.com/v1/workspaces/WORKSPACE_ID/library/UPLOAD_ID" \
-H "Authorization: Bearer YOUR_API_KEY"import requests
res = requests.delete(
"https://api.rendley.com/v1/workspaces/WORKSPACE_ID/library/UPLOAD_ID",
headers={"Authorization": "Bearer YOUR_API_KEY"},
)
data = res.json()["data"]$ch = curl_init("https://api.rendley.com/v1/workspaces/WORKSPACE_ID/library/UPLOAD_ID");
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "DELETE");
curl_setopt($ch, CURLOPT_HTTPHEADER, ["Authorization: Bearer YOUR_API_KEY"]);
$response = curl_exec($ch);
curl_close($ch);
$data = json_decode($response, true)["data"];package main
import (
"fmt"
"io"
"net/http"
)
func main() {
req, _ := http.NewRequest("DELETE", "https://api.rendley.com/v1/workspaces/WORKSPACE_ID/library/UPLOAD_ID", nil)
req.Header.Set("Authorization", "Bearer YOUR_API_KEY")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
b, _ := io.ReadAll(res.Body)
fmt.Println(string(b))
}require "net/http"
require "json"
uri = URI("https://api.rendley.com/v1/workspaces/WORKSPACE_ID/library/UPLOAD_ID")
req = Net::HTTP::Delete.new(uri)
req["Authorization"] = "Bearer YOUR_API_KEY"
res = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) { |http| http.request(req) }
data = JSON.parse(res.body)["data"]#Bridge a Library asset into a project
https://api.rendley.com/v1/workspaces/{workspaceId}/library/{uploadId}/add-to-projectServer-side copy of the asset into the project's media storage plus a role=staged upload row: the editor adopts it on reference instead of re-uploading bytes. Returns the project-side upload (media_id, file_hash, presigned URL).
const res = await fetch("https://api.rendley.com/v1/workspaces/WORKSPACE_ID/library/UPLOAD_ID/add-to-project", {
method: "POST",
headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json" },
body: JSON.stringify({
"project_id": "<project_id>"
}),
});
const { data } = await res.json();curl -X POST "https://api.rendley.com/v1/workspaces/WORKSPACE_ID/library/UPLOAD_ID/add-to-project" \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"project_id": "<project_id>"
}'import requests
res = requests.post(
"https://api.rendley.com/v1/workspaces/WORKSPACE_ID/library/UPLOAD_ID/add-to-project",
headers={"Authorization": "Bearer YOUR_API_KEY"},
json={
"project_id": "<project_id>"
},
)
data = res.json()["data"]$ch = curl_init("https://api.rendley.com/v1/workspaces/WORKSPACE_ID/library/UPLOAD_ID/add-to-project");
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "POST");
curl_setopt($ch, CURLOPT_HTTPHEADER, ["Authorization: Bearer YOUR_API_KEY", "Content-Type: application/json"]);
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode(["project_id" => "<project_id>"]));
$response = curl_exec($ch);
curl_close($ch);
$data = json_decode($response, true)["data"];package main
import (
"fmt"
"io"
"net/http"
"bytes"
)
func main() {
body := bytes.NewBufferString(`{
"project_id": "<project_id>"
}`)
req, _ := http.NewRequest("POST", "https://api.rendley.com/v1/workspaces/WORKSPACE_ID/library/UPLOAD_ID/add-to-project", body)
req.Header.Set("Authorization", "Bearer YOUR_API_KEY")
req.Header.Set("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
b, _ := io.ReadAll(res.Body)
fmt.Println(string(b))
}require "net/http"
require "json"
uri = URI("https://api.rendley.com/v1/workspaces/WORKSPACE_ID/library/UPLOAD_ID/add-to-project")
req = Net::HTTP::Post.new(uri)
req["Authorization"] = "Bearer YOUR_API_KEY"
req["Content-Type"] = "application/json"
req.body = { project_id: "<project_id>" }.to_json
res = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) { |http| http.request(req) }
data = JSON.parse(res.body)["data"]Response 200
{
"data": {
"duration": 0,
"file_hash": "c6c8ec4f9a6fdd9d",
"media_id": "c448b6e3-2b78-4bda-b369-d1afc6aec07f",
"mime_type": "string",
"original_file_name": "string",
"role": "string",
"status": "string",
"storage_url": "string"
}
}#Update a workspace Library asset's tags
Replace the asset's tag set (used to classify library media).
https://api.rendley.com/v1/workspaces/{workspaceId}/library/{uploadId}/tagsDon't have one? Create an API key
UploadID is read from the {uploadId} path segment on the public routes; the editor's flat mount still sends it in the body.
const res = await fetch("https://api.rendley.com/v1/workspaces/WORKSPACE_ID/library/UPLOAD_ID/tags", {
method: "PATCH",
headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json" },
body: JSON.stringify({
"tags": [
"string"
],
"upload_id": "<upload_id>"
}),
});
const { data } = await res.json();curl -X PATCH "https://api.rendley.com/v1/workspaces/WORKSPACE_ID/library/UPLOAD_ID/tags" \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"tags": [
"string"
],
"upload_id": "<upload_id>"
}'import requests
res = requests.patch(
"https://api.rendley.com/v1/workspaces/WORKSPACE_ID/library/UPLOAD_ID/tags",
headers={"Authorization": "Bearer YOUR_API_KEY"},
json={
"tags": [
"string"
],
"upload_id": "<upload_id>"
},
)
data = res.json()["data"]$ch = curl_init("https://api.rendley.com/v1/workspaces/WORKSPACE_ID/library/UPLOAD_ID/tags");
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "PATCH");
curl_setopt($ch, CURLOPT_HTTPHEADER, ["Authorization: Bearer YOUR_API_KEY", "Content-Type: application/json"]);
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode(["tags" => ["string"], "upload_id" => "<upload_id>"]));
$response = curl_exec($ch);
curl_close($ch);
$data = json_decode($response, true)["data"];package main
import (
"fmt"
"io"
"net/http"
"bytes"
)
func main() {
body := bytes.NewBufferString(`{
"tags": [
"string"
],
"upload_id": "<upload_id>"
}`)
req, _ := http.NewRequest("PATCH", "https://api.rendley.com/v1/workspaces/WORKSPACE_ID/library/UPLOAD_ID/tags", body)
req.Header.Set("Authorization", "Bearer YOUR_API_KEY")
req.Header.Set("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
b, _ := io.ReadAll(res.Body)
fmt.Println(string(b))
}require "net/http"
require "json"
uri = URI("https://api.rendley.com/v1/workspaces/WORKSPACE_ID/library/UPLOAD_ID/tags")
req = Net::HTTP::Patch.new(uri)
req["Authorization"] = "Bearer YOUR_API_KEY"
req["Content-Type"] = "application/json"
req.body = { tags: ["string"], upload_id: "<upload_id>" }.to_json
res = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) { |http| http.request(req) }
data = JSON.parse(res.body)["data"]Response 200
{
"data": {
"created_at": "string",
"deduplicated": true,
"download_url": "string",
"duration": 0,
"file_hash": "c6c8ec4f9a6fdd9d",
"file_size": 0,
"id": "3f0d5a4e-3d2a-4c1f-9b3e-2a1c4d5e6f70",
"media_id": "c448b6e3-2b78-4bda-b369-d1afc6aec07f",
"mime_type": "string",
"original_file_name": "string",
"source": "string",
"tags": [
"string"
],
"thumbnail_url": "string",
"url": "string",
"workspace_id": "3f0d5a4e-3d2a-4c1f-9b3e-2a1c4d5e6f70"
}
}#Abort a chunked server-hashed Library upload
Discards the in-progress session, its stored parts, and the pending asset row.
https://api.rendley.com/v1/workspaces/{workspaceId}/library/chunked/{uploadId}/abortDon't have one? Create an API key
const res = await fetch("https://api.rendley.com/v1/workspaces/WORKSPACE_ID/library/chunked/UPLOAD_ID/abort", {
method: "POST",
headers: { Authorization: "Bearer YOUR_API_KEY" },
});
const { data } = await res.json();curl -X POST "https://api.rendley.com/v1/workspaces/WORKSPACE_ID/library/chunked/UPLOAD_ID/abort" \
-H "Authorization: Bearer YOUR_API_KEY"import requests
res = requests.post(
"https://api.rendley.com/v1/workspaces/WORKSPACE_ID/library/chunked/UPLOAD_ID/abort",
headers={"Authorization": "Bearer YOUR_API_KEY"},
)
data = res.json()["data"]$ch = curl_init("https://api.rendley.com/v1/workspaces/WORKSPACE_ID/library/chunked/UPLOAD_ID/abort");
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "POST");
curl_setopt($ch, CURLOPT_HTTPHEADER, ["Authorization: Bearer YOUR_API_KEY"]);
$response = curl_exec($ch);
curl_close($ch);
$data = json_decode($response, true)["data"];package main
import (
"fmt"
"io"
"net/http"
)
func main() {
req, _ := http.NewRequest("POST", "https://api.rendley.com/v1/workspaces/WORKSPACE_ID/library/chunked/UPLOAD_ID/abort", nil)
req.Header.Set("Authorization", "Bearer YOUR_API_KEY")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
b, _ := io.ReadAll(res.Body)
fmt.Println(string(b))
}require "net/http"
require "json"
uri = URI("https://api.rendley.com/v1/workspaces/WORKSPACE_ID/library/chunked/UPLOAD_ID/abort")
req = Net::HTTP::Post.new(uri)
req["Authorization"] = "Bearer YOUR_API_KEY"
res = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) { |http| http.request(req) }
data = JSON.parse(res.body)["data"]#Complete a chunked server-hashed Library upload
https://api.rendley.com/v1/workspaces/{workspaceId}/library/chunked/{uploadId}/completeAssembles the parts and finalizes the asset with the server-computed hash. Requires every declared byte to have arrived. Dedup-aware: identical existing content is returned with deduplicated=true.
Don't have one? Create an API key
const res = await fetch("https://api.rendley.com/v1/workspaces/WORKSPACE_ID/library/chunked/UPLOAD_ID/complete", {
method: "POST",
headers: { Authorization: "Bearer YOUR_API_KEY" },
});
const { data } = await res.json();curl -X POST "https://api.rendley.com/v1/workspaces/WORKSPACE_ID/library/chunked/UPLOAD_ID/complete" \
-H "Authorization: Bearer YOUR_API_KEY"import requests
res = requests.post(
"https://api.rendley.com/v1/workspaces/WORKSPACE_ID/library/chunked/UPLOAD_ID/complete",
headers={"Authorization": "Bearer YOUR_API_KEY"},
)
data = res.json()["data"]$ch = curl_init("https://api.rendley.com/v1/workspaces/WORKSPACE_ID/library/chunked/UPLOAD_ID/complete");
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "POST");
curl_setopt($ch, CURLOPT_HTTPHEADER, ["Authorization: Bearer YOUR_API_KEY"]);
$response = curl_exec($ch);
curl_close($ch);
$data = json_decode($response, true)["data"];package main
import (
"fmt"
"io"
"net/http"
)
func main() {
req, _ := http.NewRequest("POST", "https://api.rendley.com/v1/workspaces/WORKSPACE_ID/library/chunked/UPLOAD_ID/complete", nil)
req.Header.Set("Authorization", "Bearer YOUR_API_KEY")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
b, _ := io.ReadAll(res.Body)
fmt.Println(string(b))
}require "net/http"
require "json"
uri = URI("https://api.rendley.com/v1/workspaces/WORKSPACE_ID/library/chunked/UPLOAD_ID/complete")
req = Net::HTTP::Post.new(uri)
req["Authorization"] = "Bearer YOUR_API_KEY"
res = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) { |http| http.request(req) }
data = JSON.parse(res.body)["data"]Response 200
{
"data": {
"created_at": "string",
"deduplicated": true,
"download_url": "string",
"duration": 0,
"file_hash": "c6c8ec4f9a6fdd9d",
"file_size": 0,
"id": "3f0d5a4e-3d2a-4c1f-9b3e-2a1c4d5e6f70",
"media_id": "c448b6e3-2b78-4bda-b369-d1afc6aec07f",
"mime_type": "string",
"original_file_name": "string",
"source": "string",
"tags": [
"string"
],
"thumbnail_url": "string",
"url": "string",
"workspace_id": "3f0d5a4e-3d2a-4c1f-9b3e-2a1c4d5e6f70"
}
}#Upload one part of a chunked Library upload
https://api.rendley.com/v1/workspaces/{workspaceId}/library/chunked/{uploadId}/parts/{partNumber}Raw part bytes as the request body. Parts must be sent strictly in order (409 CHUNK_OUT_OF_ORDER carries the expected part number); only the final part may be under the minimum part size. Content-Length is required.
Don't have one? Create an API key
const res = await fetch("https://api.rendley.com/v1/workspaces/WORKSPACE_ID/library/chunked/UPLOAD_ID/parts/PART_NUMBER", {
method: "PUT",
headers: { Authorization: "Bearer YOUR_API_KEY" },
});
const { data } = await res.json();curl -X PUT "https://api.rendley.com/v1/workspaces/WORKSPACE_ID/library/chunked/UPLOAD_ID/parts/PART_NUMBER" \
-H "Authorization: Bearer YOUR_API_KEY"import requests
res = requests.put(
"https://api.rendley.com/v1/workspaces/WORKSPACE_ID/library/chunked/UPLOAD_ID/parts/PART_NUMBER",
headers={"Authorization": "Bearer YOUR_API_KEY"},
)
data = res.json()["data"]$ch = curl_init("https://api.rendley.com/v1/workspaces/WORKSPACE_ID/library/chunked/UPLOAD_ID/parts/PART_NUMBER");
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "PUT");
curl_setopt($ch, CURLOPT_HTTPHEADER, ["Authorization: Bearer YOUR_API_KEY"]);
$response = curl_exec($ch);
curl_close($ch);
$data = json_decode($response, true)["data"];package main
import (
"fmt"
"io"
"net/http"
)
func main() {
req, _ := http.NewRequest("PUT", "https://api.rendley.com/v1/workspaces/WORKSPACE_ID/library/chunked/UPLOAD_ID/parts/PART_NUMBER", nil)
req.Header.Set("Authorization", "Bearer YOUR_API_KEY")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
b, _ := io.ReadAll(res.Body)
fmt.Println(string(b))
}require "net/http"
require "json"
uri = URI("https://api.rendley.com/v1/workspaces/WORKSPACE_ID/library/chunked/UPLOAD_ID/parts/PART_NUMBER")
req = Net::HTTP::Put.new(uri)
req["Authorization"] = "Bearer YOUR_API_KEY"
res = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) { |http| http.request(req) }
data = JSON.parse(res.body)["data"]Response 200
{
"data": {
"next_part": 0,
"received_bytes": 0
}
}#Start a chunked server-hashed Library upload
https://api.rendley.com/v1/workspaces/{workspaceId}/library/chunked/initiateHashless large-file transport for API/MCP clients that cannot compute XXH64: parts are PUT to the API strictly in order, the server hashes them incrementally while forwarding to storage, and the hash exists at complete: computed server-side. Files under the proxy cap should use the single-call proxy upload instead.
const res = await fetch("https://api.rendley.com/v1/workspaces/WORKSPACE_ID/library/chunked/initiate", {
method: "POST",
headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json" },
body: JSON.stringify({
"file_size": 0
}),
});
const { data } = await res.json();curl -X POST "https://api.rendley.com/v1/workspaces/WORKSPACE_ID/library/chunked/initiate" \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"file_size": 0
}'import requests
res = requests.post(
"https://api.rendley.com/v1/workspaces/WORKSPACE_ID/library/chunked/initiate",
headers={"Authorization": "Bearer YOUR_API_KEY"},
json={
"file_size": 0
},
)
data = res.json()["data"]$ch = curl_init("https://api.rendley.com/v1/workspaces/WORKSPACE_ID/library/chunked/initiate");
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "POST");
curl_setopt($ch, CURLOPT_HTTPHEADER, ["Authorization: Bearer YOUR_API_KEY", "Content-Type: application/json"]);
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode(["file_size" => 0]));
$response = curl_exec($ch);
curl_close($ch);
$data = json_decode($response, true)["data"];package main
import (
"fmt"
"io"
"net/http"
"bytes"
)
func main() {
body := bytes.NewBufferString(`{
"file_size": 0
}`)
req, _ := http.NewRequest("POST", "https://api.rendley.com/v1/workspaces/WORKSPACE_ID/library/chunked/initiate", body)
req.Header.Set("Authorization", "Bearer YOUR_API_KEY")
req.Header.Set("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
b, _ := io.ReadAll(res.Body)
fmt.Println(string(b))
}require "net/http"
require "json"
uri = URI("https://api.rendley.com/v1/workspaces/WORKSPACE_ID/library/chunked/initiate")
req = Net::HTTP::Post.new(uri)
req["Authorization"] = "Bearer YOUR_API_KEY"
req["Content-Type"] = "application/json"
req.body = { file_size: 0 }.to_json
res = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) { |http| http.request(req) }
data = JSON.parse(res.body)["data"]Response 200
{
"data": {
"part_size_max": 0,
"part_size_min": 0,
"upload_id": "3f0d5a4e-3d2a-4c1f-9b3e-2a1c4d5e6f70"
}
}#Add a project's media file to the workspace Library
https://api.rendley.com/v1/workspaces/{workspaceId}/library/from-projectCopies the media (resolved by project ID + content hash) into the Library server-side: no bytes transit the client. Returns the existing asset with deduplicated=true when identical content is already in the Library.
const res = await fetch("https://api.rendley.com/v1/workspaces/WORKSPACE_ID/library/from-project", {
method: "POST",
headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json" },
body: JSON.stringify({
"file_hash": "<file_hash>",
"project_id": "<project_id>"
}),
});
const { data } = await res.json();curl -X POST "https://api.rendley.com/v1/workspaces/WORKSPACE_ID/library/from-project" \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"file_hash": "<file_hash>",
"project_id": "<project_id>"
}'import requests
res = requests.post(
"https://api.rendley.com/v1/workspaces/WORKSPACE_ID/library/from-project",
headers={"Authorization": "Bearer YOUR_API_KEY"},
json={
"file_hash": "<file_hash>",
"project_id": "<project_id>"
},
)
data = res.json()["data"]$ch = curl_init("https://api.rendley.com/v1/workspaces/WORKSPACE_ID/library/from-project");
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "POST");
curl_setopt($ch, CURLOPT_HTTPHEADER, ["Authorization: Bearer YOUR_API_KEY", "Content-Type: application/json"]);
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode(["file_hash" => "<file_hash>", "project_id" => "<project_id>"]));
$response = curl_exec($ch);
curl_close($ch);
$data = json_decode($response, true)["data"];package main
import (
"fmt"
"io"
"net/http"
"bytes"
)
func main() {
body := bytes.NewBufferString(`{
"file_hash": "<file_hash>",
"project_id": "<project_id>"
}`)
req, _ := http.NewRequest("POST", "https://api.rendley.com/v1/workspaces/WORKSPACE_ID/library/from-project", body)
req.Header.Set("Authorization", "Bearer YOUR_API_KEY")
req.Header.Set("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
b, _ := io.ReadAll(res.Body)
fmt.Println(string(b))
}require "net/http"
require "json"
uri = URI("https://api.rendley.com/v1/workspaces/WORKSPACE_ID/library/from-project")
req = Net::HTTP::Post.new(uri)
req["Authorization"] = "Bearer YOUR_API_KEY"
req["Content-Type"] = "application/json"
req.body = { file_hash: "<file_hash>", project_id: "<project_id>" }.to_json
res = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) { |http| http.request(req) }
data = JSON.parse(res.body)["data"]Response 200
{
"data": {
"created_at": "string",
"deduplicated": true,
"download_url": "string",
"duration": 0,
"file_hash": "c6c8ec4f9a6fdd9d",
"file_size": 0,
"id": "3f0d5a4e-3d2a-4c1f-9b3e-2a1c4d5e6f70",
"media_id": "c448b6e3-2b78-4bda-b369-d1afc6aec07f",
"mime_type": "string",
"original_file_name": "string",
"source": "string",
"tags": [
"string"
],
"thumbnail_url": "string",
"url": "string",
"workspace_id": "3f0d5a4e-3d2a-4c1f-9b3e-2a1c4d5e6f70"
}
}#Abort a chunked Library upload
Discard an in-progress multipart upload and its pending asset row.
https://api.rendley.com/v1/workspaces/{workspaceId}/library/multipart/abortconst res = await fetch("https://api.rendley.com/v1/workspaces/WORKSPACE_ID/library/multipart/abort", {
method: "POST",
headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json" },
body: JSON.stringify({
"s3_upload_id": "<s3_upload_id>",
"upload_id": "<upload_id>"
}),
});
const { data } = await res.json();curl -X POST "https://api.rendley.com/v1/workspaces/WORKSPACE_ID/library/multipart/abort" \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"s3_upload_id": "<s3_upload_id>",
"upload_id": "<upload_id>"
}'import requests
res = requests.post(
"https://api.rendley.com/v1/workspaces/WORKSPACE_ID/library/multipart/abort",
headers={"Authorization": "Bearer YOUR_API_KEY"},
json={
"s3_upload_id": "<s3_upload_id>",
"upload_id": "<upload_id>"
},
)
data = res.json()["data"]$ch = curl_init("https://api.rendley.com/v1/workspaces/WORKSPACE_ID/library/multipart/abort");
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "POST");
curl_setopt($ch, CURLOPT_HTTPHEADER, ["Authorization: Bearer YOUR_API_KEY", "Content-Type: application/json"]);
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode(["s3_upload_id" => "<s3_upload_id>", "upload_id" => "<upload_id>"]));
$response = curl_exec($ch);
curl_close($ch);
$data = json_decode($response, true)["data"];package main
import (
"fmt"
"io"
"net/http"
"bytes"
)
func main() {
body := bytes.NewBufferString(`{
"s3_upload_id": "<s3_upload_id>",
"upload_id": "<upload_id>"
}`)
req, _ := http.NewRequest("POST", "https://api.rendley.com/v1/workspaces/WORKSPACE_ID/library/multipart/abort", body)
req.Header.Set("Authorization", "Bearer YOUR_API_KEY")
req.Header.Set("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
b, _ := io.ReadAll(res.Body)
fmt.Println(string(b))
}require "net/http"
require "json"
uri = URI("https://api.rendley.com/v1/workspaces/WORKSPACE_ID/library/multipart/abort")
req = Net::HTTP::Post.new(uri)
req["Authorization"] = "Bearer YOUR_API_KEY"
req["Content-Type"] = "application/json"
req.body = { s3_upload_id: "<s3_upload_id>", upload_id: "<upload_id>" }.to_json
res = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) { |http| http.request(req) }
data = JSON.parse(res.body)["data"]#Complete a chunked Library upload
Assemble the uploaded parts into the final object and mark the asset complete. Quota is charged from the size the bucket actually stored.
https://api.rendley.com/v1/workspaces/{workspaceId}/library/multipart/completeconst res = await fetch("https://api.rendley.com/v1/workspaces/WORKSPACE_ID/library/multipart/complete", {
method: "POST",
headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json" },
body: JSON.stringify({
"parts": [
{
"etag": "string",
"part_number": 0
}
],
"s3_upload_id": "<s3_upload_id>",
"upload_id": "<upload_id>"
}),
});
const { data } = await res.json();curl -X POST "https://api.rendley.com/v1/workspaces/WORKSPACE_ID/library/multipart/complete" \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"parts": [
{
"etag": "string",
"part_number": 0
}
],
"s3_upload_id": "<s3_upload_id>",
"upload_id": "<upload_id>"
}'import requests
res = requests.post(
"https://api.rendley.com/v1/workspaces/WORKSPACE_ID/library/multipart/complete",
headers={"Authorization": "Bearer YOUR_API_KEY"},
json={
"parts": [
{
"etag": "string",
"part_number": 0
}
],
"s3_upload_id": "<s3_upload_id>",
"upload_id": "<upload_id>"
},
)
data = res.json()["data"]$ch = curl_init("https://api.rendley.com/v1/workspaces/WORKSPACE_ID/library/multipart/complete");
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "POST");
curl_setopt($ch, CURLOPT_HTTPHEADER, ["Authorization: Bearer YOUR_API_KEY", "Content-Type: application/json"]);
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode(["parts" => [["etag" => "string", "part_number" => 0]], "s3_upload_id" => "<s3_upload_id>", "upload_id" => "<upload_id>"]));
$response = curl_exec($ch);
curl_close($ch);
$data = json_decode($response, true)["data"];package main
import (
"fmt"
"io"
"net/http"
"bytes"
)
func main() {
body := bytes.NewBufferString(`{
"parts": [
{
"etag": "string",
"part_number": 0
}
],
"s3_upload_id": "<s3_upload_id>",
"upload_id": "<upload_id>"
}`)
req, _ := http.NewRequest("POST", "https://api.rendley.com/v1/workspaces/WORKSPACE_ID/library/multipart/complete", body)
req.Header.Set("Authorization", "Bearer YOUR_API_KEY")
req.Header.Set("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
b, _ := io.ReadAll(res.Body)
fmt.Println(string(b))
}require "net/http"
require "json"
uri = URI("https://api.rendley.com/v1/workspaces/WORKSPACE_ID/library/multipart/complete")
req = Net::HTTP::Post.new(uri)
req["Authorization"] = "Bearer YOUR_API_KEY"
req["Content-Type"] = "application/json"
req.body = { parts: [{ etag: "string", part_number: 0 }], s3_upload_id: "<s3_upload_id>", upload_id: "<upload_id>" }.to_json
res = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) { |http| http.request(req) }
data = JSON.parse(res.body)["data"]Response 200
{
"data": {
"created_at": "string",
"deduplicated": true,
"download_url": "string",
"duration": 0,
"file_hash": "c6c8ec4f9a6fdd9d",
"file_size": 0,
"id": "3f0d5a4e-3d2a-4c1f-9b3e-2a1c4d5e6f70",
"media_id": "c448b6e3-2b78-4bda-b369-d1afc6aec07f",
"mime_type": "string",
"original_file_name": "string",
"source": "string",
"tags": [
"string"
],
"thumbnail_url": "string",
"url": "string",
"workspace_id": "3f0d5a4e-3d2a-4c1f-9b3e-2a1c4d5e6f70"
}
}#Start a chunked Library upload (large-file transport)
https://api.rendley.com/v1/workspaces/{workspaceId}/library/multipart/initiateFor files above the proxy cap: records a pending asset and returns presigned part URLs pointing straight at object storage. Finish with the multipart complete call. When identical content already exists in the Library the response carries existing (deduplicated=true) instead of an upload session: skip the transfer.
Don't have one? Create an API key
FileHash is required: multipart bytes go client→bucket, so the client is the only party that ever holds the full stream: every completed library row must carry its content hash (XXH64, 16 hex chars).
Source provenance; clients may claim "uploaded" (default) or "export".
Transient uploads are scratch input for an AI job: never listed as a Library asset, unmetered, removed by the daily stale-upload sweep. Reference by upload id only.
const res = await fetch("https://api.rendley.com/v1/workspaces/WORKSPACE_ID/library/multipart/initiate", {
method: "POST",
headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json" },
body: JSON.stringify({
"file_hash": "<file_hash>",
"file_size": 0,
"part_count": 0
}),
});
const { data } = await res.json();curl -X POST "https://api.rendley.com/v1/workspaces/WORKSPACE_ID/library/multipart/initiate" \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"file_hash": "<file_hash>",
"file_size": 0,
"part_count": 0
}'import requests
res = requests.post(
"https://api.rendley.com/v1/workspaces/WORKSPACE_ID/library/multipart/initiate",
headers={"Authorization": "Bearer YOUR_API_KEY"},
json={
"file_hash": "<file_hash>",
"file_size": 0,
"part_count": 0
},
)
data = res.json()["data"]$ch = curl_init("https://api.rendley.com/v1/workspaces/WORKSPACE_ID/library/multipart/initiate");
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "POST");
curl_setopt($ch, CURLOPT_HTTPHEADER, ["Authorization: Bearer YOUR_API_KEY", "Content-Type: application/json"]);
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode(["file_hash" => "<file_hash>", "file_size" => 0, "part_count" => 0]));
$response = curl_exec($ch);
curl_close($ch);
$data = json_decode($response, true)["data"];package main
import (
"fmt"
"io"
"net/http"
"bytes"
)
func main() {
body := bytes.NewBufferString(`{
"file_hash": "<file_hash>",
"file_size": 0,
"part_count": 0
}`)
req, _ := http.NewRequest("POST", "https://api.rendley.com/v1/workspaces/WORKSPACE_ID/library/multipart/initiate", body)
req.Header.Set("Authorization", "Bearer YOUR_API_KEY")
req.Header.Set("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
b, _ := io.ReadAll(res.Body)
fmt.Println(string(b))
}require "net/http"
require "json"
uri = URI("https://api.rendley.com/v1/workspaces/WORKSPACE_ID/library/multipart/initiate")
req = Net::HTTP::Post.new(uri)
req["Authorization"] = "Bearer YOUR_API_KEY"
req["Content-Type"] = "application/json"
req.body = { file_hash: "<file_hash>", file_size: 0, part_count: 0 }.to_json
res = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) { |http| http.request(req) }
data = JSON.parse(res.body)["data"]Response 200
{
"data": {
"existing": {
"created_at": "string",
"deduplicated": true,
"download_url": "string",
"duration": 0,
"file_hash": "c6c8ec4f9a6fdd9d",
"file_size": 0,
"id": "3f0d5a4e-3d2a-4c1f-9b3e-2a1c4d5e6f70",
"media_id": "c448b6e3-2b78-4bda-b369-d1afc6aec07f",
"mime_type": "string",
"original_file_name": "string",
"source": "string",
"tags": [
"string"
],
"thumbnail_url": "string",
"url": "string",
"workspace_id": "3f0d5a4e-3d2a-4c1f-9b3e-2a1c4d5e6f70"
},
"media_id": "c448b6e3-2b78-4bda-b369-d1afc6aec07f",
"presigned_urls": [
{
"part_number": 0,
"url": "string"
}
],
"s3_upload_id": "3f0d5a4e-3d2a-4c1f-9b3e-2a1c4d5e6f70",
"upload_id": "3f0d5a4e-3d2a-4c1f-9b3e-2a1c4d5e6f70"
}
}#Upload scratch input for an AI job
https://api.rendley.com/v1/workspaces/{workspaceId}/library/transientStream raw file bytes to be used as an AI job input without adding them to the Library: the file is never listed as an asset, charges no storage, and is removed by the daily stale-upload sweep. Reference it in the job's params by the returned id only. Content-Length is required.
Don't have one? Create an API key
const res = await fetch("https://api.rendley.com/v1/workspaces/WORKSPACE_ID/library/transient", {
method: "POST",
headers: { Authorization: "Bearer YOUR_API_KEY" },
});
const { data } = await res.json();curl -X POST "https://api.rendley.com/v1/workspaces/WORKSPACE_ID/library/transient" \
-H "Authorization: Bearer YOUR_API_KEY"import requests
res = requests.post(
"https://api.rendley.com/v1/workspaces/WORKSPACE_ID/library/transient",
headers={"Authorization": "Bearer YOUR_API_KEY"},
)
data = res.json()["data"]$ch = curl_init("https://api.rendley.com/v1/workspaces/WORKSPACE_ID/library/transient");
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "POST");
curl_setopt($ch, CURLOPT_HTTPHEADER, ["Authorization: Bearer YOUR_API_KEY"]);
$response = curl_exec($ch);
curl_close($ch);
$data = json_decode($response, true)["data"];package main
import (
"fmt"
"io"
"net/http"
)
func main() {
req, _ := http.NewRequest("POST", "https://api.rendley.com/v1/workspaces/WORKSPACE_ID/library/transient", nil)
req.Header.Set("Authorization", "Bearer YOUR_API_KEY")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
b, _ := io.ReadAll(res.Body)
fmt.Println(string(b))
}require "net/http"
require "json"
uri = URI("https://api.rendley.com/v1/workspaces/WORKSPACE_ID/library/transient")
req = Net::HTTP::Post.new(uri)
req["Authorization"] = "Bearer YOUR_API_KEY"
res = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) { |http| http.request(req) }
data = JSON.parse(res.body)["data"]Response 200
{
"data": {
"created_at": "string",
"deduplicated": true,
"download_url": "string",
"duration": 0,
"file_hash": "c6c8ec4f9a6fdd9d",
"file_size": 0,
"id": "3f0d5a4e-3d2a-4c1f-9b3e-2a1c4d5e6f70",
"media_id": "c448b6e3-2b78-4bda-b369-d1afc6aec07f",
"mime_type": "string",
"original_file_name": "string",
"source": "string",
"tags": [
"string"
],
"thumbnail_url": "string",
"url": "string",
"workspace_id": "3f0d5a4e-3d2a-4c1f-9b3e-2a1c4d5e6f70"
}
}