curl --request POST \
--url https://api.trycarhub.com/v1/assets \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: multipart/form-data' \
--form 'name=<string>' \
--form 'file=<string>'import requests
url = "https://api.trycarhub.com/v1/assets"
payload = "-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"name\"\r\n\r\n<string>\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"file\"\r\n\r\n<string>\r\n-----011000010111000001101001--"
headers = {
"Authorization": "Bearer <token>",
"Content-Type": "multipart/form-data"
}
response = requests.post(url, data=payload, headers=headers)
print(response.text)const form = new FormData();
form.append('name', '<string>');
form.append('file', '<string>');
const options = {method: 'POST', headers: {Authorization: 'Bearer <token>'}};
options.body = form;
fetch('https://api.trycarhub.com/v1/assets', 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://api.trycarhub.com/v1/assets",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => "-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"name\"\r\n\r\n<string>\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"file\"\r\n\r\n<string>\r\n-----011000010111000001101001--",
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>",
"Content-Type: multipart/form-data"
],
]);
$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://api.trycarhub.com/v1/assets"
payload := strings.NewReader("-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"name\"\r\n\r\n<string>\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"file\"\r\n\r\n<string>\r\n-----011000010111000001101001--")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("Authorization", "Bearer <token>")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://api.trycarhub.com/v1/assets")
.header("Authorization", "Bearer <token>")
.body("-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"name\"\r\n\r\n<string>\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"file\"\r\n\r\n<string>\r\n-----011000010111000001101001--")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.trycarhub.com/v1/assets")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Authorization"] = 'Bearer <token>'
request.body = "-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"name\"\r\n\r\n<string>\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"file\"\r\n\r\n<string>\r\n-----011000010111000001101001--"
response = http.request(request)
puts response.read_body{
"id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"object": "asset",
"category": "background",
"kind": "background",
"name": "<string>",
"content_type": "<string>",
"size_bytes": 1,
"total_size_bytes": 1,
"state": "available",
"created": 1755300000,
"banner_placement": "top",
"background_id": 123,
"link": "<string>",
"download_url": "<string>",
"files": [
{
"path": "<string>",
"size_bytes": 1,
"download_url": "<string>"
}
]
}Upload a permanent organization asset
Requires assets:write. Upload a file up to 25 MiB. PNG, JPEG, and WebP are accepted
for logo, license_plate, and banner; misc accepts any file type and is
downloaded as an attachment. Send category, or the legacy kind alias. When
both are present, they must match. Banners require banner_placement.
For background, send the complete Studio multipart package: image,
non_floor_rgba, floor_rgba, to_ignore_mask, generated yaml, interior_id,
and optional JSON-encoded brands. All package files count toward storage.
Existing background routes and custom--<ID> selectors remain supported.
Space is reserved before writing to the dedicated private assets bucket. Assets have no automatic expiration and share the existing organization storage quota with inputs. Partial uploads remain charged until their removal is confirmed.
curl --request POST \
--url https://api.trycarhub.com/v1/assets \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: multipart/form-data' \
--form 'name=<string>' \
--form 'file=<string>'import requests
url = "https://api.trycarhub.com/v1/assets"
payload = "-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"name\"\r\n\r\n<string>\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"file\"\r\n\r\n<string>\r\n-----011000010111000001101001--"
headers = {
"Authorization": "Bearer <token>",
"Content-Type": "multipart/form-data"
}
response = requests.post(url, data=payload, headers=headers)
print(response.text)const form = new FormData();
form.append('name', '<string>');
form.append('file', '<string>');
const options = {method: 'POST', headers: {Authorization: 'Bearer <token>'}};
options.body = form;
fetch('https://api.trycarhub.com/v1/assets', 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://api.trycarhub.com/v1/assets",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => "-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"name\"\r\n\r\n<string>\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"file\"\r\n\r\n<string>\r\n-----011000010111000001101001--",
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>",
"Content-Type: multipart/form-data"
],
]);
$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://api.trycarhub.com/v1/assets"
payload := strings.NewReader("-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"name\"\r\n\r\n<string>\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"file\"\r\n\r\n<string>\r\n-----011000010111000001101001--")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("Authorization", "Bearer <token>")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://api.trycarhub.com/v1/assets")
.header("Authorization", "Bearer <token>")
.body("-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"name\"\r\n\r\n<string>\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"file\"\r\n\r\n<string>\r\n-----011000010111000001101001--")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.trycarhub.com/v1/assets")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Authorization"] = 'Bearer <token>'
request.body = "-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"name\"\r\n\r\n<string>\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"file\"\r\n\r\n<string>\r\n-----011000010111000001101001--"
response = http.request(request)
puts response.read_body{
"id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"object": "asset",
"category": "background",
"kind": "background",
"name": "<string>",
"content_type": "<string>",
"size_bytes": 1,
"total_size_bytes": 1,
"state": "available",
"created": 1755300000,
"banner_placement": "top",
"background_id": 123,
"link": "<string>",
"download_url": "<string>",
"files": [
{
"path": "<string>",
"size_bytes": 1,
"download_url": "<string>"
}
]
}Authorizations
Organisation API key, sent as Authorization: Bearer chk_live_….
chk_live_…— production inference, live credits,livemode: true,is_staging: false.chk_stg_…— real inference classified as staging, the same live credits,livemode: true,is_staging: true.chk_test_…— identical pipeline against the fixture backend, test credits,livemode: false.
Keys are stored hashed; only the prefix (chk_live_a1b2…) is ever displayed again. A key
may be scoped to a subset of endpoint families — calling outside its scopes is a 403.
Body
- Option 1
- Option 2
- Option 3
- Option 4
license_plate, banner, logo, misc 1 - 200File up to 25 MiB. Images must be PNG, JPEG, or WebP; misc accepts any type.
Legacy alias. If both selectors are sent, they must match.
license_plate, banner, logo, misc Required for category banner.
top, bottom Response
Asset uploaded.
Permanent organization asset. Scene size includes all image layers and YAML. Only available assets have signed links and can be selected for new jobs.
Asset UUID, including for custom background scenes.
"asset"background, license_plate, banner, logo, misc Legacy alias of category, retained for existing clients.
background, license_plate, banner, logo, misc Total bytes in the asset package.
x >= 0Total bytes including all scene layers and YAML.
x >= 0available, uploading, deleting, delete_failed, deleted Epoch seconds, UTC.
1755300000
top, bottom, null Historical numeric scene ID used in custom-- selectors.
Short-lived signed preview URL. Empty or omitted for unavailable assets; misc files use attachment downloads.
Short-lived signed download URL. Uses attachment Content-Disposition for misc files. Empty or omitted when unavailable.
Background package files returned by GET for an available scene. Includes all layers and YAML with individual signed download URLs. Omitted when unavailable.
Show child attributes
Show child attributes