API reference
Uploads
Project-level media. Add files to a single project, list what it holds, and use multipart uploads when a file is too large to send in one request.
#List uploads
https://api.rendley.com/v1/projects/{projectId}/uploadsList uploads for a project, or get a single upload by media_id (or file hash). An optional role filter scopes the list to one lifecycle role (the editor's hash sync passes role=library so pending/transient files are invisible to its reconciliation; the pending poller passes role=pending).
Don't have one? Create an API key
const res = await fetch("https://api.rendley.com/v1/projects/PROJECT_ID/uploads", {
headers: { Authorization: "Bearer YOUR_API_KEY" },
});
const { data } = await res.json();curl "https://api.rendley.com/v1/projects/PROJECT_ID/uploads" \
-H "Authorization: Bearer YOUR_API_KEY"import requests
res = requests.get(
"https://api.rendley.com/v1/projects/PROJECT_ID/uploads",
headers={"Authorization": "Bearer YOUR_API_KEY"},
)
data = res.json()["data"]$ch = curl_init("https://api.rendley.com/v1/projects/PROJECT_ID/uploads");
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/projects/PROJECT_ID/uploads", 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/projects/PROJECT_ID/uploads")
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": [
{
"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"
}
]
}#Create an upload
https://api.rendley.com/v1/projects/{projectId}/uploadsRegister a file and get a presigned URL to PUT its bytes to, then call the complete endpoint. media_id and file_hash are optional for API keys: the server generates the media_id (returned in the response) and records a placeholder hash. Use the media_id as the media reference of AI actions once the upload is complete.
Don't have one? Create an API key
FileHash is the client-computed XXH64 content hash (16 hex chars). Optional for API keys.
MediaId is the client-chosen media id (a UUID). Optional for API keys.
Role is the sync-lifecycle tag: "library" (reconciled by the editor's hash sync), "pending" (awaiting auto-injection into the library; invisible to the sync), "staged" (agent/AI workflow file; invisible to the sync AND not auto-injected: adopted to library only when explicitly referenced) or "transient" (never a library asset). Defaults to "library"; "pending" when Source is "mcp"; "staged" for API-key requests (so opening the project in the editor never reaps an API-uploaded file before it is referenced).
Source is provenance: which flow created the upload.
const res = await fetch("https://api.rendley.com/v1/projects/PROJECT_ID/uploads", {
method: "POST",
headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json" },
body: JSON.stringify({
"duration": 0,
"file_hash": "<file_hash>",
"file_size": 0
}),
});
const { data } = await res.json();curl -X POST "https://api.rendley.com/v1/projects/PROJECT_ID/uploads" \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"duration": 0,
"file_hash": "<file_hash>",
"file_size": 0
}'import requests
res = requests.post(
"https://api.rendley.com/v1/projects/PROJECT_ID/uploads",
headers={"Authorization": "Bearer YOUR_API_KEY"},
json={
"duration": 0,
"file_hash": "<file_hash>",
"file_size": 0
},
)
data = res.json()["data"]$ch = curl_init("https://api.rendley.com/v1/projects/PROJECT_ID/uploads");
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(["duration" => 0, "file_hash" => "<file_hash>", "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(`{
"duration": 0,
"file_hash": "<file_hash>",
"file_size": 0
}`)
req, _ := http.NewRequest("POST", "https://api.rendley.com/v1/projects/PROJECT_ID/uploads", 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/projects/PROJECT_ID/uploads")
req = Net::HTTP::Post.new(uri)
req["Authorization"] = "Bearer YOUR_API_KEY"
req["Content-Type"] = "application/json"
req.body = { duration: 0, file_hash: "<file_hash>", 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": {
"media_id": "c448b6e3-2b78-4bda-b369-d1afc6aec07f",
"presigned_url": "string",
"upload_id": "3f0d5a4e-3d2a-4c1f-9b3e-2a1c4d5e6f70"
}
}#Delete an upload
Delete a project upload by its media ID.
https://api.rendley.com/v1/projects/{projectId}/uploads/{mediaId}Don't have one? Create an API key
const res = await fetch("https://api.rendley.com/v1/projects/PROJECT_ID/uploads/MEDIA_ID", {
method: "DELETE",
headers: { Authorization: "Bearer YOUR_API_KEY" },
});
const { data } = await res.json();curl -X DELETE "https://api.rendley.com/v1/projects/PROJECT_ID/uploads/MEDIA_ID" \
-H "Authorization: Bearer YOUR_API_KEY"import requests
res = requests.delete(
"https://api.rendley.com/v1/projects/PROJECT_ID/uploads/MEDIA_ID",
headers={"Authorization": "Bearer YOUR_API_KEY"},
)
data = res.json()["data"]$ch = curl_init("https://api.rendley.com/v1/projects/PROJECT_ID/uploads/MEDIA_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/projects/PROJECT_ID/uploads/MEDIA_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/projects/PROJECT_ID/uploads/MEDIA_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"]#Complete an upload
https://api.rendley.com/v1/projects/{projectId}/uploads/{uploadId}/completeMark a single upload as completed by its ID once the bytes have been PUT to the presigned URL. Returns the completed upload, including the media_id to use as the media reference of AI actions.
Don't have one? Create an API key
const res = await fetch("https://api.rendley.com/v1/projects/PROJECT_ID/uploads/UPLOAD_ID/complete", {
method: "POST",
headers: { Authorization: "Bearer YOUR_API_KEY" },
});
const { data } = await res.json();curl -X POST "https://api.rendley.com/v1/projects/PROJECT_ID/uploads/UPLOAD_ID/complete" \
-H "Authorization: Bearer YOUR_API_KEY"import requests
res = requests.post(
"https://api.rendley.com/v1/projects/PROJECT_ID/uploads/UPLOAD_ID/complete",
headers={"Authorization": "Bearer YOUR_API_KEY"},
)
data = res.json()["data"]$ch = curl_init("https://api.rendley.com/v1/projects/PROJECT_ID/uploads/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/projects/PROJECT_ID/uploads/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/projects/PROJECT_ID/uploads/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": {
"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"
}
}#Create a batch of uploads
Create multiple uploads at once, returning presigned URLs for accepted files and reasons for rejected ones.
https://api.rendley.com/v1/projects/{projectId}/uploads/batchDon't have one? Create an API key
filesrequiredFileHash is the client-computed XXH64 content hash (16 hex chars). Optional for API keys.
MediaId is the client-chosen media id (a UUID). Optional for API keys.
Role is the sync-lifecycle tag: "library" (reconciled by the editor's hash sync), "pending" (awaiting auto-injection into the library; invisible to the sync), "staged" (agent/AI workflow file; invisible to the sync AND not auto-injected: adopted to library only when explicitly referenced) or "transient" (never a library asset). Defaults to "library"; "pending" when Source is "mcp"; "staged" for API-key requests (so opening the project in the editor never reaps an API-uploaded file before it is referenced).
Source is provenance: which flow created the upload.
const res = await fetch("https://api.rendley.com/v1/projects/PROJECT_ID/uploads/batch", {
method: "POST",
headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json" },
body: JSON.stringify({
"files": [
{
"duration": 0,
"file_hash": "c6c8ec4f9a6fdd9d",
"file_size": 0,
"media_id": "3f0d5a4e-3d2a-4c1f-9b3e-2a1c4d5e6f70",
"metadata": "string",
"mime_type": "string",
"original_file_name": "string",
"project_id": "3f0d5a4e-3d2a-4c1f-9b3e-2a1c4d5e6f70",
"role": "library",
"source": "editor"
}
]
}),
});
const { data } = await res.json();curl -X POST "https://api.rendley.com/v1/projects/PROJECT_ID/uploads/batch" \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"files": [
{
"duration": 0,
"file_hash": "c6c8ec4f9a6fdd9d",
"file_size": 0,
"media_id": "3f0d5a4e-3d2a-4c1f-9b3e-2a1c4d5e6f70",
"metadata": "string",
"mime_type": "string",
"original_file_name": "string",
"project_id": "3f0d5a4e-3d2a-4c1f-9b3e-2a1c4d5e6f70",
"role": "library",
"source": "editor"
}
]
}'import requests
res = requests.post(
"https://api.rendley.com/v1/projects/PROJECT_ID/uploads/batch",
headers={"Authorization": "Bearer YOUR_API_KEY"},
json={
"files": [
{
"duration": 0,
"file_hash": "c6c8ec4f9a6fdd9d",
"file_size": 0,
"media_id": "3f0d5a4e-3d2a-4c1f-9b3e-2a1c4d5e6f70",
"metadata": "string",
"mime_type": "string",
"original_file_name": "string",
"project_id": "3f0d5a4e-3d2a-4c1f-9b3e-2a1c4d5e6f70",
"role": "library",
"source": "editor"
}
]
},
)
data = res.json()["data"]$ch = curl_init("https://api.rendley.com/v1/projects/PROJECT_ID/uploads/batch");
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(["files" => [["duration" => 0, "file_hash" => "c6c8ec4f9a6fdd9d", "file_size" => 0, "media_id" => "3f0d5a4e-3d2a-4c1f-9b3e-2a1c4d5e6f70", "metadata" => "string", "mime_type" => "string", "original_file_name" => "string", "project_id" => "3f0d5a4e-3d2a-4c1f-9b3e-2a1c4d5e6f70", "role" => "library", "source" => "editor"]]]));
$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(`{
"files": [
{
"duration": 0,
"file_hash": "c6c8ec4f9a6fdd9d",
"file_size": 0,
"media_id": "3f0d5a4e-3d2a-4c1f-9b3e-2a1c4d5e6f70",
"metadata": "string",
"mime_type": "string",
"original_file_name": "string",
"project_id": "3f0d5a4e-3d2a-4c1f-9b3e-2a1c4d5e6f70",
"role": "library",
"source": "editor"
}
]
}`)
req, _ := http.NewRequest("POST", "https://api.rendley.com/v1/projects/PROJECT_ID/uploads/batch", 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/projects/PROJECT_ID/uploads/batch")
req = Net::HTTP::Post.new(uri)
req["Authorization"] = "Bearer YOUR_API_KEY"
req["Content-Type"] = "application/json"
req.body = { files: [{ duration: 0, file_hash: "c6c8ec4f9a6fdd9d", file_size: 0, media_id: "3f0d5a4e-3d2a-4c1f-9b3e-2a1c4d5e6f70", metadata: "string", mime_type: "string", original_file_name: "string", project_id: "3f0d5a4e-3d2a-4c1f-9b3e-2a1c4d5e6f70", role: "library", source: "editor" }] }.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": {
"items": [
{
"media_id": "c448b6e3-2b78-4bda-b369-d1afc6aec07f",
"presigned_url": "string",
"upload_id": "3f0d5a4e-3d2a-4c1f-9b3e-2a1c4d5e6f70"
}
],
"rejected": [
{
"media_id": "c448b6e3-2b78-4bda-b369-d1afc6aec07f",
"reason": "string"
}
]
}
}#Complete a batch of uploads
Mark a batch of uploads as completed by their upload IDs.
https://api.rendley.com/v1/projects/{projectId}/uploads/batch/completeconst res = await fetch("https://api.rendley.com/v1/projects/PROJECT_ID/uploads/batch/complete", {
method: "POST",
headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json" },
body: JSON.stringify({
"upload_ids": [
"3f0d5a4e-3d2a-4c1f-9b3e-2a1c4d5e6f70"
]
}),
});
const { data } = await res.json();curl -X POST "https://api.rendley.com/v1/projects/PROJECT_ID/uploads/batch/complete" \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"upload_ids": [
"3f0d5a4e-3d2a-4c1f-9b3e-2a1c4d5e6f70"
]
}'import requests
res = requests.post(
"https://api.rendley.com/v1/projects/PROJECT_ID/uploads/batch/complete",
headers={"Authorization": "Bearer YOUR_API_KEY"},
json={
"upload_ids": [
"3f0d5a4e-3d2a-4c1f-9b3e-2a1c4d5e6f70"
]
},
)
data = res.json()["data"]$ch = curl_init("https://api.rendley.com/v1/projects/PROJECT_ID/uploads/batch/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(["upload_ids" => ["3f0d5a4e-3d2a-4c1f-9b3e-2a1c4d5e6f70"]]));
$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(`{
"upload_ids": [
"3f0d5a4e-3d2a-4c1f-9b3e-2a1c4d5e6f70"
]
}`)
req, _ := http.NewRequest("POST", "https://api.rendley.com/v1/projects/PROJECT_ID/uploads/batch/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/projects/PROJECT_ID/uploads/batch/complete")
req = Net::HTTP::Post.new(uri)
req["Authorization"] = "Bearer YOUR_API_KEY"
req["Content-Type"] = "application/json"
req.body = { upload_ids: ["3f0d5a4e-3d2a-4c1f-9b3e-2a1c4d5e6f70"] }.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": {
"completed": 0,
"failed": [
{
"error": "string",
"upload_id": "3f0d5a4e-3d2a-4c1f-9b3e-2a1c4d5e6f70"
}
]
}
}#Import an upload from a URL
https://api.rendley.com/v1/projects/{projectId}/uploads/importOne-call upload for a file that is already hosted: the server downloads it from a public HTTPS direct link, stores it and returns the completed upload. Use the returned media_id as the media reference of AI actions. No client-side hashing or presigned PUT is needed. The host must report Content-Length; files are capped at 5 GB.
const res = await fetch("https://api.rendley.com/v1/projects/PROJECT_ID/uploads/import", {
method: "POST",
headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json" },
body: JSON.stringify({
"download_url": "<download_url>"
}),
});
const { data } = await res.json();curl -X POST "https://api.rendley.com/v1/projects/PROJECT_ID/uploads/import" \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"download_url": "<download_url>"
}'import requests
res = requests.post(
"https://api.rendley.com/v1/projects/PROJECT_ID/uploads/import",
headers={"Authorization": "Bearer YOUR_API_KEY"},
json={
"download_url": "<download_url>"
},
)
data = res.json()["data"]$ch = curl_init("https://api.rendley.com/v1/projects/PROJECT_ID/uploads/import");
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(["download_url" => "<download_url>"]));
$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(`{
"download_url": "<download_url>"
}`)
req, _ := http.NewRequest("POST", "https://api.rendley.com/v1/projects/PROJECT_ID/uploads/import", 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/projects/PROJECT_ID/uploads/import")
req = Net::HTTP::Post.new(uri)
req["Authorization"] = "Bearer YOUR_API_KEY"
req["Content-Type"] = "application/json"
req.body = { download_url: "<download_url>" }.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"
}
}#Abort a multipart upload
Abort an in-progress multipart upload.
https://api.rendley.com/v1/projects/{projectId}/uploads/multipart/abortconst res = await fetch("https://api.rendley.com/v1/projects/PROJECT_ID/uploads/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/projects/PROJECT_ID/uploads/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/projects/PROJECT_ID/uploads/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/projects/PROJECT_ID/uploads/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/projects/PROJECT_ID/uploads/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/projects/PROJECT_ID/uploads/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 multipart upload
Complete a multipart upload by submitting the uploaded parts.
https://api.rendley.com/v1/projects/{projectId}/uploads/multipart/completeconst res = await fetch("https://api.rendley.com/v1/projects/PROJECT_ID/uploads/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/projects/PROJECT_ID/uploads/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/projects/PROJECT_ID/uploads/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/projects/PROJECT_ID/uploads/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/projects/PROJECT_ID/uploads/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/projects/PROJECT_ID/uploads/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"]#Initiate a multipart upload
https://api.rendley.com/v1/projects/{projectId}/uploads/multipart/initiateFor large files: register the file and get presigned URLs for each part, PUT the parts, then call the multipart complete endpoint with their ETags. media_id and file_hash are optional for API keys (see the create upload endpoint); the response carries the media_id.
Don't have one? Create an API key
FileHash is the client-computed XXH64 content hash (16 hex chars). Optional for API keys.
MediaId is the client-chosen media id (a UUID). Optional for API keys.
Role is the sync-lifecycle tag: "library" (reconciled by the editor's hash sync), "pending" (awaiting auto-injection into the library; invisible to the sync), "staged" (agent/AI workflow file; invisible to the sync AND not auto-injected: adopted to library only when explicitly referenced) or "transient" (never a library asset). Defaults to "library"; "pending" when Source is "mcp"; "staged" for API-key requests (so opening the project in the editor never reaps an API-uploaded file before it is referenced).
Source is provenance: which flow created the upload.
const res = await fetch("https://api.rendley.com/v1/projects/PROJECT_ID/uploads/multipart/initiate", {
method: "POST",
headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json" },
body: JSON.stringify({
"part_count": 0
}),
});
const { data } = await res.json();curl -X POST "https://api.rendley.com/v1/projects/PROJECT_ID/uploads/multipart/initiate" \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"part_count": 0
}'import requests
res = requests.post(
"https://api.rendley.com/v1/projects/PROJECT_ID/uploads/multipart/initiate",
headers={"Authorization": "Bearer YOUR_API_KEY"},
json={
"part_count": 0
},
)
data = res.json()["data"]$ch = curl_init("https://api.rendley.com/v1/projects/PROJECT_ID/uploads/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(["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(`{
"part_count": 0
}`)
req, _ := http.NewRequest("POST", "https://api.rendley.com/v1/projects/PROJECT_ID/uploads/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/projects/PROJECT_ID/uploads/multipart/initiate")
req = Net::HTTP::Post.new(uri)
req["Authorization"] = "Bearer YOUR_API_KEY"
req["Content-Type"] = "application/json"
req.body = { 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": {
"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"
}
}