Assets

Manage 3D models, textures, and graphics. Upload, organize, and retrieve assets with signed download URLs.

List Assets

GET/assets
// Get all assets (optionally filter by type)
const response = await fetch(BASE_URL + '/assets?type=3d', {
  headers: { 'Authorization': 'Bearer ' + accessToken }
});

Upload Asset

POST/assets
const formData = new FormData();
formData.append('file', fileInput.files[0]);
formData.append('name', 'Chair Model');
formData.append('type', '3d');
formData.append('category', 'furniture');

const response = await fetch(BASE_URL + '/assets', {
  method: 'POST',
  headers: { 'Authorization': 'Bearer ' + accessToken },
  body: formData
});

Get Asset

GET/assets/:assetId
const response = await fetch(BASE_URL + '/assets/asset_123', {
  headers: { 'Authorization': 'Bearer ' + accessToken }
});

Update Asset

PUT/assets/:assetId
const response = await fetch(BASE_URL + '/assets/asset_123', {
  method: 'PUT',
  headers: {
    'Authorization': 'Bearer ' + accessToken,
    'Content-Type': 'application/json'
  },
  body: JSON.stringify({ name: 'Renamed Asset', category: 'new-category' })
});

Delete Asset

DELETE/assets/:assetId
const response = await fetch(BASE_URL + '/assets/asset_123', {
  method: 'DELETE',
  headers: { 'Authorization': 'Bearer ' + accessToken }
});

Download Asset (binary or signed URL)

GET/assets/:assetId/download
// Returns the RAW FILE, not JSON — do not call response.json().
const response = await fetch(BASE_URL + '/assets/asset_123/download', {
  headers: { 'Authorization': 'Bearer ' + accessToken }
});

const bytes = await response.arrayBuffer();
// Content-Type: application/octet-stream
// Content-Disposition: attachment; filename="model.glb"

// For an asset that came from a template, pass the project so the server can
// fall back to the template owner's copy:
// GET /assets/asset_123/download?projectId=YOUR_PROJECT_ID
//
// NOTE: by default this endpoint streams the file through the API. Very large
// models can exceed the platform's 150s request ceiling.

// OPT-IN: ?mode=signed-url returns JSON instead, and the browser fetches the
// bytes straight from storage — no Edge buffering, so no 150s ceiling.
// The default stays the raw file: that response is a published contract and
// switching it would break every existing consumer.
const meta = await fetch(
  BASE_URL + '/assets/asset_123/download?mode=signed-url',
  { headers: { 'Authorization': 'Bearer ' + accessToken } }
).then(r => r.json());
// { success: true, signedUrl: "https://…", fileName: "model.glb" }
const bytes2 = await (await fetch(meta.signedUrl)).arrayBuffer();

// An older deployment ignores ?mode= and returns the binary, so feature-detect
// on the Content-Type rather than assuming JSON.

Continue reading