Uploads
#List uploads
/v1/uploadsList uploads for a project, or get a single upload when a file hash is provided. 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).
Query parameters
project_idstringRequiredProject ID
hashstringOptionalFile hash to fetch a single upload
rolestringOptionalFilter by lifecycle role
Response codes
200OK
400Bad Request
401Unauthorized
403Forbidden
curl "https://api.rendley.com/v1/uploads?project_id=PROJECT_ID" \
-H "Authorization: Bearer YOUR_API_KEY"const res = await fetch("https://api.rendley.com/v1/uploads?project_id=PROJECT_ID", {
headers: { Authorization: "Bearer YOUR_API_KEY" },
});
const { data } = await res.json();import requests
res = requests.get(
"https://api.rendley.com/v1/uploads?project_id=PROJECT_ID",
headers={"Authorization": "Bearer YOUR_API_KEY"},
)
data = res.json()["data"]$ch = curl_init("https://api.rendley.com/v1/uploads?project_id=PROJECT_ID");
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/uploads?project_id=PROJECT_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/uploads?project_id=PROJECT_ID")
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": [
{
"duration": 0,
"file_hash": "string",
"media_id": "string",
"mime_type": "string",
"original_file_name": "string",
"role": "string",
"status": "string",
"storage_url": "string"
}
]
}#Create an upload
/v1/uploadsCreate a single upload and get a presigned URL to upload the file bytes to.
Request body
durationnumberOptionalfile_hashstringRequiredfile_sizeintegerOptionalmedia_idstringRequiredmetadatastringOptionalmime_typestringOptionaloriginal_file_namestringOptionalproject_idstringRequiredrole"library" | "pending" | "staged" | "transient"OptionalRole 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", or "pending" when Source is "mcp".
source"editor" | "mcp" | "agent" | "export" | "ai" | "duplicate"OptionalSource is provenance: which flow created the upload.
Response codes
200OK
400Bad Request
401Unauthorized
403Forbidden
curl -X POST "https://api.rendley.com/v1/uploads" \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"file_hash": "<file_hash>",
"media_id": "<media_id>",
"project_id": "<project_id>"
}'const res = await fetch("https://api.rendley.com/v1/uploads", {
method: "POST",
headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json" },
body: JSON.stringify({
"file_hash": "<file_hash>",
"media_id": "<media_id>",
"project_id": "<project_id>"
}),
});
const { data } = await res.json();import requests
res = requests.post(
"https://api.rendley.com/v1/uploads",
headers={"Authorization": "Bearer YOUR_API_KEY"},
json={
"file_hash": "<file_hash>",
"media_id": "<media_id>",
"project_id": "<project_id>"
},
)
data = res.json()["data"]$ch = curl_init("https://api.rendley.com/v1/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(["file_hash" => "<file_hash>", "media_id" => "<media_id>", "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>",
"media_id": "<media_id>",
"project_id": "<project_id>"
}`)
req, _ := http.NewRequest("POST", "https://api.rendley.com/v1/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/uploads")
req = Net::HTTP::Post.new(uri)
req["Authorization"] = "Bearer YOUR_API_KEY"
req["Content-Type"] = "application/json"
req.body = { file_hash: "<file_hash>", media_id: "<media_id>", 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"]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", or "pending" when Source is "mcp".
Source is provenance: which flow created the upload.
Response
{
"data": {
"presigned_url": "string",
"upload_id": "string"
}
}#Delete an upload
/v1/uploadsDelete an upload from a project by its file hash. With scope=library the delete only applies to role=library rows (a no-op otherwise) — the editor's hash sync uses this so it can never remove pending or transient files. Without scope, any role is deleted (daemons/cleanup flows rely on this).
Query parameters
project_idstringRequiredProject ID
hashstringRequiredFile hash of the upload to delete
scopestringOptionalRestrict the delete to a lifecycle role
Response codes
200OK
400Bad Request
401Unauthorized
403Forbidden
curl -X DELETE "https://api.rendley.com/v1/uploads?project_id=PROJECT_ID&hash=HASH" \
-H "Authorization: Bearer YOUR_API_KEY"const res = await fetch("https://api.rendley.com/v1/uploads?project_id=PROJECT_ID&hash=HASH", {
method: "DELETE",
headers: { Authorization: "Bearer YOUR_API_KEY" },
});
const { data } = await res.json();import requests
res = requests.delete(
"https://api.rendley.com/v1/uploads?project_id=PROJECT_ID&hash=HASH",
headers={"Authorization": "Bearer YOUR_API_KEY"},
)
data = res.json()["data"]$ch = curl_init("https://api.rendley.com/v1/uploads?project_id=PROJECT_ID&hash=HASH");
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/uploads?project_id=PROJECT_ID&hash=HASH", 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/uploads?project_id=PROJECT_ID&hash=HASH")
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
/v1/uploads/{id}/completeMark a single upload as completed by its ID.
Path parameters
idstringUpload ID
Response codes
200OK
401Unauthorized
404Not Found
curl -X POST "https://api.rendley.com/v1/uploads/ID/complete" \
-H "Authorization: Bearer YOUR_API_KEY"const res = await fetch("https://api.rendley.com/v1/uploads/ID/complete", {
method: "POST",
headers: { Authorization: "Bearer YOUR_API_KEY" },
});
const { data } = await res.json();import requests
res = requests.post(
"https://api.rendley.com/v1/uploads/ID/complete",
headers={"Authorization": "Bearer YOUR_API_KEY"},
)
data = res.json()["data"]$ch = curl_init("https://api.rendley.com/v1/uploads/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/uploads/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/uploads/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"]#Adopt pending/staged uploads into the library
/v1/uploads/adoptRetag role=pending and role=staged uploads to role=library for the given file hashes, making them visible to the editor's hash sync, and return the hashes that flipped. For pending rows call only AFTER the project JSON referencing these files has been saved; staged rows are adopted by the editor at the moment it would otherwise upload the bytes.
Request body
file_hashesstring[]Requiredproject_idstringRequiredResponse codes
200OK
400Bad Request
401Unauthorized
403Forbidden
curl -X POST "https://api.rendley.com/v1/uploads/adopt" \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"file_hashes": [
"string"
],
"project_id": "<project_id>"
}'const res = await fetch("https://api.rendley.com/v1/uploads/adopt", {
method: "POST",
headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json" },
body: JSON.stringify({
"file_hashes": [
"string"
],
"project_id": "<project_id>"
}),
});
const { data } = await res.json();import requests
res = requests.post(
"https://api.rendley.com/v1/uploads/adopt",
headers={"Authorization": "Bearer YOUR_API_KEY"},
json={
"file_hashes": [
"string"
],
"project_id": "<project_id>"
},
)
data = res.json()["data"]$ch = curl_init("https://api.rendley.com/v1/uploads/adopt");
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_hashes" => ["string"], "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_hashes": [
"string"
],
"project_id": "<project_id>"
}`)
req, _ := http.NewRequest("POST", "https://api.rendley.com/v1/uploads/adopt", 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/uploads/adopt")
req = Net::HTTP::Post.new(uri)
req["Authorization"] = "Bearer YOUR_API_KEY"
req["Content-Type"] = "application/json"
req.body = { file_hashes: ["string"], 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": {
"adopted": 0,
"adopted_hashes": [
"string"
]
}
}#Create a batch of uploads
/v1/uploads/batchCreate multiple uploads at once, returning presigned URLs for accepted files and reasons for rejected ones.
Request body
filesobject[]RequireddurationnumberOptionalfile_hashstringRequiredfile_sizeintegerOptionalmedia_idstringRequiredmetadatastringOptionalmime_typestringOptionaloriginal_file_namestringOptionalproject_idstringRequiredrole"library" | "pending" | "staged" | "transient"OptionalRole 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", or "pending" when Source is "mcp".
source"editor" | "mcp" | "agent" | "export" | "ai" | "duplicate"OptionalSource is provenance: which flow created the upload.
project_idstringRequiredResponse codes
200OK
400Bad Request
401Unauthorized
403Forbidden
curl -X POST "https://api.rendley.com/v1/uploads/batch" \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"files": [
{
"duration": 0,
"file_hash": "string",
"file_size": 0,
"media_id": "string",
"metadata": "string",
"mime_type": "string",
"original_file_name": "string",
"project_id": "string",
"role": "library",
"source": "editor"
}
],
"project_id": "<project_id>"
}'const res = await fetch("https://api.rendley.com/v1/uploads/batch", {
method: "POST",
headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json" },
body: JSON.stringify({
"files": [
{
"duration": 0,
"file_hash": "string",
"file_size": 0,
"media_id": "string",
"metadata": "string",
"mime_type": "string",
"original_file_name": "string",
"project_id": "string",
"role": "library",
"source": "editor"
}
],
"project_id": "<project_id>"
}),
});
const { data } = await res.json();import requests
res = requests.post(
"https://api.rendley.com/v1/uploads/batch",
headers={"Authorization": "Bearer YOUR_API_KEY"},
json={
"files": [
{
"duration": 0,
"file_hash": "string",
"file_size": 0,
"media_id": "string",
"metadata": "string",
"mime_type": "string",
"original_file_name": "string",
"project_id": "string",
"role": "library",
"source": "editor"
}
],
"project_id": "<project_id>"
},
)
data = res.json()["data"]$ch = curl_init("https://api.rendley.com/v1/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" => "string", "file_size" => 0, "media_id" => "string", "metadata" => "string", "mime_type" => "string", "original_file_name" => "string", "project_id" => "string", "role" => "library", "source" => "editor"]], "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(`{
"files": [
{
"duration": 0,
"file_hash": "string",
"file_size": 0,
"media_id": "string",
"metadata": "string",
"mime_type": "string",
"original_file_name": "string",
"project_id": "string",
"role": "library",
"source": "editor"
}
],
"project_id": "<project_id>"
}`)
req, _ := http.NewRequest("POST", "https://api.rendley.com/v1/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/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: "string", file_size: 0, media_id: "string", metadata: "string", mime_type: "string", original_file_name: "string", project_id: "string", role: "library", source: "editor" }], 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"]filesREQUIREDRole 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", or "pending" when Source is "mcp".
Source is provenance: which flow created the upload.
Response
{
"data": {
"items": [
{
"media_id": "string",
"presigned_url": "string",
"upload_id": "string"
}
],
"rejected": [
{
"media_id": "string",
"reason": "string"
}
]
}
}#Complete a batch of uploads
/v1/uploads/batch/completeMark a batch of uploads as completed by their upload IDs.
Request body
upload_idsstring[]RequiredResponse codes
200OK
400Bad Request
401Unauthorized
curl -X POST "https://api.rendley.com/v1/uploads/batch/complete" \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"upload_ids": [
"string"
]
}'const res = await fetch("https://api.rendley.com/v1/uploads/batch/complete", {
method: "POST",
headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json" },
body: JSON.stringify({
"upload_ids": [
"string"
]
}),
});
const { data } = await res.json();import requests
res = requests.post(
"https://api.rendley.com/v1/uploads/batch/complete",
headers={"Authorization": "Bearer YOUR_API_KEY"},
json={
"upload_ids": [
"string"
]
},
)
data = res.json()["data"]$ch = curl_init("https://api.rendley.com/v1/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" => ["string"]]));
$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": [
"string"
]
}`)
req, _ := http.NewRequest("POST", "https://api.rendley.com/v1/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/uploads/batch/complete")
req = Net::HTTP::Post.new(uri)
req["Authorization"] = "Bearer YOUR_API_KEY"
req["Content-Type"] = "application/json"
req.body = { upload_ids: ["string"] }.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": {
"completed": 0,
"failed": [
{
"error": "string",
"upload_id": "string"
}
]
}
}#Abort a multipart upload
/v1/uploads/multipart/abortAbort an in-progress multipart upload.
Request body
s3_upload_idstringRequiredupload_idstringRequiredResponse codes
200OK
400Bad Request
401Unauthorized
curl -X POST "https://api.rendley.com/v1/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>"
}'const res = await fetch("https://api.rendley.com/v1/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();import requests
res = requests.post(
"https://api.rendley.com/v1/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/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/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/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
/v1/uploads/multipart/completeComplete a multipart upload by submitting the uploaded parts.
Request body
partsobject[]RequiredetagstringRequiredpart_numberintegerRequireds3_upload_idstringRequiredupload_idstringRequiredResponse codes
200OK
400Bad Request
401Unauthorized
curl -X POST "https://api.rendley.com/v1/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>"
}'const res = await fetch("https://api.rendley.com/v1/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();import requests
res = requests.post(
"https://api.rendley.com/v1/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/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/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/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"]partsREQUIRED#Initiate a multipart upload
/v1/uploads/multipart/initiateInitiate a multipart upload and get presigned URLs for each part.
Request body
durationnumberOptionalfile_hashstringRequiredfile_sizeintegerOptionalmedia_idstringRequiredmetadatastringOptionalmime_typestringOptionaloriginal_file_namestringOptionalpart_countintegerRequiredproject_idstringRequiredrole"library" | "pending" | "staged" | "transient"OptionalRole 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", or "pending" when Source is "mcp".
source"editor" | "mcp" | "agent" | "export" | "ai" | "duplicate"OptionalSource is provenance: which flow created the upload.
Response codes
200OK
400Bad Request
401Unauthorized
403Forbidden
curl -X POST "https://api.rendley.com/v1/uploads/multipart/initiate" \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"file_hash": "<file_hash>",
"media_id": "<media_id>",
"part_count": 0,
"project_id": "<project_id>"
}'const res = await fetch("https://api.rendley.com/v1/uploads/multipart/initiate", {
method: "POST",
headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json" },
body: JSON.stringify({
"file_hash": "<file_hash>",
"media_id": "<media_id>",
"part_count": 0,
"project_id": "<project_id>"
}),
});
const { data } = await res.json();import requests
res = requests.post(
"https://api.rendley.com/v1/uploads/multipart/initiate",
headers={"Authorization": "Bearer YOUR_API_KEY"},
json={
"file_hash": "<file_hash>",
"media_id": "<media_id>",
"part_count": 0,
"project_id": "<project_id>"
},
)
data = res.json()["data"]$ch = curl_init("https://api.rendley.com/v1/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(["file_hash" => "<file_hash>", "media_id" => "<media_id>", "part_count" => 0, "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>",
"media_id": "<media_id>",
"part_count": 0,
"project_id": "<project_id>"
}`)
req, _ := http.NewRequest("POST", "https://api.rendley.com/v1/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/uploads/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>", media_id: "<media_id>", part_count: 0, 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"]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", or "pending" when Source is "mcp".
Source is provenance: which flow created the upload.
Response
{
"data": {
"presigned_urls": [
{
"part_number": 0,
"url": "string"
}
],
"s3_upload_id": "string",
"upload_id": "string"
}
}