Rendley docs

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.

GEThttps://api.rendley.com/v1/workspaces/{workspaceId}/library

Don'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

{
  "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)

POSThttps://api.rendley.com/v1/workspaces/{workspaceId}/library

Single-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

{
  "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.

PATCHhttps://api.rendley.com/v1/workspaces/{workspaceId}/library/{uploadId}

Don't have one? Create an API key

Body

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

{
  "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.

DELETEhttps://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

POSThttps://api.rendley.com/v1/workspaces/{workspaceId}/library/{uploadId}/add-to-project

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

Don't have one? Create an API key

Body
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

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

PATCHhttps://api.rendley.com/v1/workspaces/{workspaceId}/library/{uploadId}/tags

Don't have one? Create an API key

Body

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

{
  "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.

POSThttps://api.rendley.com/v1/workspaces/{workspaceId}/library/chunked/{uploadId}/abort

Don'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

POSThttps://api.rendley.com/v1/workspaces/{workspaceId}/library/chunked/{uploadId}/complete

Assembles 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

{
  "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

PUThttps://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

{
  "data": {
    "next_part": 0,
    "received_bytes": 0
  }
}

#Start a chunked server-hashed Library upload

POSThttps://api.rendley.com/v1/workspaces/{workspaceId}/library/chunked/initiate

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

Don't have one? Create an API key

Body
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

{
  "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

POSThttps://api.rendley.com/v1/workspaces/{workspaceId}/library/from-project

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

Don't have one? Create an API key

Body
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

{
  "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.

POSThttps://api.rendley.com/v1/workspaces/{workspaceId}/library/multipart/abort

Don't have one? Create an API key

Body
const 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.

POSThttps://api.rendley.com/v1/workspaces/{workspaceId}/library/multipart/complete

Don't have one? Create an API key

Body
partsrequiredobject[]
const 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

{
  "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)

POSThttps://api.rendley.com/v1/workspaces/{workspaceId}/library/multipart/initiate

For 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

Body

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

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

{
  "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"
    },
    "presigned_urls": [
      {
        "part_number": 0,
        "url": "string"
      }
    ],
    "s3_upload_id": "3f0d5a4e-3d2a-4c1f-9b3e-2a1c4d5e6f70",
    "upload_id": "3f0d5a4e-3d2a-4c1f-9b3e-2a1c4d5e6f70"
  }
}