Register a direct-uploaded file as an asset
curl --request POST \
--url https://mvp.tryunsora.com/api/v1/uploads/complete \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"blobName": "<string>",
"fileName": "<string>"
}
'import requests
url = "https://mvp.tryunsora.com/api/v1/uploads/complete"
payload = {
"blobName": "<string>",
"fileName": "<string>"
}
headers = {
"Authorization": "Bearer <token>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'},
body: JSON.stringify({blobName: '<string>', fileName: '<string>'})
};
fetch('https://mvp.tryunsora.com/api/v1/uploads/complete', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://mvp.tryunsora.com/api/v1/uploads/complete",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'blobName' => '<string>',
'fileName' => '<string>'
]),
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>",
"Content-Type: application/json"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://mvp.tryunsora.com/api/v1/uploads/complete"
payload := strings.NewReader("{\n \"blobName\": \"<string>\",\n \"fileName\": \"<string>\"\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("Authorization", "Bearer <token>")
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://mvp.tryunsora.com/api/v1/uploads/complete")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"blobName\": \"<string>\",\n \"fileName\": \"<string>\"\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://mvp.tryunsora.com/api/v1/uploads/complete")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Authorization"] = 'Bearer <token>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"blobName\": \"<string>\",\n \"fileName\": \"<string>\"\n}"
response = http.request(request)
puts response.read_body{
"success": true,
"data": {
"id": "<string>",
"name": "<string>",
"url": "<string>",
"mimeType": "<string>",
"type": "IMAGE",
"fileSize": 123,
"createdAt": "2023-11-07T05:31:56Z"
}
}{
"error": "<string>",
"success": true,
"code": "<string>",
"message": "<string>"
}{
"error": "<string>",
"success": true,
"code": "<string>",
"message": "<string>"
}Uploads
Complete upload
Register a file uploaded via signed URL as a media library asset so it can be used in posts, clips, and generation jobs.
POST
/
uploads
/
complete
Register a direct-uploaded file as an asset
curl --request POST \
--url https://mvp.tryunsora.com/api/v1/uploads/complete \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"blobName": "<string>",
"fileName": "<string>"
}
'import requests
url = "https://mvp.tryunsora.com/api/v1/uploads/complete"
payload = {
"blobName": "<string>",
"fileName": "<string>"
}
headers = {
"Authorization": "Bearer <token>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'},
body: JSON.stringify({blobName: '<string>', fileName: '<string>'})
};
fetch('https://mvp.tryunsora.com/api/v1/uploads/complete', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://mvp.tryunsora.com/api/v1/uploads/complete",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'blobName' => '<string>',
'fileName' => '<string>'
]),
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>",
"Content-Type: application/json"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://mvp.tryunsora.com/api/v1/uploads/complete"
payload := strings.NewReader("{\n \"blobName\": \"<string>\",\n \"fileName\": \"<string>\"\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("Authorization", "Bearer <token>")
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://mvp.tryunsora.com/api/v1/uploads/complete")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"blobName\": \"<string>\",\n \"fileName\": \"<string>\"\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://mvp.tryunsora.com/api/v1/uploads/complete")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Authorization"] = 'Bearer <token>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"blobName\": \"<string>\",\n \"fileName\": \"<string>\"\n}"
response = http.request(request)
puts response.read_body{
"success": true,
"data": {
"id": "<string>",
"name": "<string>",
"url": "<string>",
"mimeType": "<string>",
"type": "IMAGE",
"fileSize": 123,
"createdAt": "2023-11-07T05:31:56Z"
}
}{
"error": "<string>",
"success": true,
"code": "<string>",
"message": "<string>"
}{
"error": "<string>",
"success": true,
"code": "<string>",
"message": "<string>"
}Final step of the signed-URL flow: after
PUTting the file bytes to the signed uploadUrl, call this with the
blobName from the same response to record the file as an asset in your media
library.
The server verifies the object actually exists in storage (you get a 400 if
the PUT didn’t happen) and reads its size and MIME type from storage
metadata. blobName must come from your own signed-URL response — blobs
outside your upload prefix are rejected with 403. fileSize is null when storage doesn’t report a size.
Response
Same shape as POST /uploads:{
"success": true,
"data": {
"id": "cm456def",
"name": "big-video.mp4",
"url": "https://.../uploads/usr_123/2026-08-04T10-00-00-000Z-big-video.mp4",
"mimeType": "video/mp4",
"type": "VIDEO",
"fileSize": 209715200,
"createdAt": "2026-08-04T10:00:00.000Z"
}
}

