Populate the library
The rendering workflow starts from a model, but a workspace library holds more than models: props to dress scenes, decals to apply to surfaces, and materials to swap onto products. Each has its own API surface, and they all follow the same shape as models: create a record and get a signed upload URL, PUT the file, confirm, then poll status until it is ready.
Everything on this page is also available to AI agents through the Glossi MCP connector; the same server code backs both.
Import a model from a URL
When a model already lives at a public URL (a CDN, a signed cloud-storage link, a supplier's download page), Glossi can fetch it for you instead of you streaming the bytes through your integration.
POST https://api.glossi.io/api/v1/models/importcurl -X POST https://api.glossi.io/api/v1/models/import \
-H "X-API-Key: glsi_xxxxxxxxxx_xxxxx" \
-H "Content-Type: application/json" \
-d '{"url": "https://cdn.example.com/models/chair.glb", "name": "Chair"}'Response (202 Accepted):
{
"modelId": "abc123-uuid",
"name": "Chair",
"fileType": "glb",
"status": "UPLOADING"
}| Field | Required | Description |
|---|---|---|
url | Yes | Public http(s) URL. Private network addresses are refused, and every redirect is checked the same way |
name | No | Library name. Defaults to the file name in the URL |
fileType | No | File extension. Needed when the URL path has no extension, which signed links often lack |
The download and confirm run in the background. Poll POST /models/status as in the complete workflow: the model moves UPLOADING → PENDING → ANALYZING → READY. If the download fails, the model is left FAILED and its status entry carries an error field with the reason. Files are capped at 1 GB.
Upload props
Props are 3D files that dress a scene: furniture, plants, packaging. They accept the same formats as models and go through the same converter.
Create props and get upload URLs
POST https://api.glossi.io/api/v1/propscurl -X POST https://api.glossi.io/api/v1/props \
-H "X-API-Key: glsi_xxxxxxxxxx_xxxxx" \
-H "Content-Type: application/json" \
-d '{
"props": [
{ "fileName": "wooden_stool.glb", "collection": "Furniture" },
{ "fileName": "fern.fbx", "collection": "Plants" }
]
}'Response (201 Created):
{
"props": [
{
"propId": "prop-uuid-1",
"name": "Wooden Stool",
"uploadUrl": "https://s3.amazonaws.com/...",
"uploadKey": "workspaces/.../PROPS/prop-uuid-1/model.glb"
},
{
"propId": "prop-uuid-2",
"name": "Fern",
"uploadUrl": "https://s3.amazonaws.com/...",
"uploadKey": "workspaces/.../PROPS/prop-uuid-2/model.fbx"
}
]
}Up to 50 props per request. collection is a name, not an id: the collection is created in your workspace the first time you use it and matched by name after that. name is optional and defaults to a cleaned-up file name.
Upload and confirm
PUT each file to its uploadUrl within one hour, then confirm each prop:
curl -X PUT "https://s3.amazonaws.com/..." --data-binary @wooden_stool.glb
curl -X POST https://api.glossi.io/api/v1/props/prop-uuid-1/confirm \
-H "X-API-Key: glsi_xxxxxxxxxx_xxxxx"Wait until ready
curl -X POST https://api.glossi.io/api/v1/props/status \
-H "X-API-Key: glsi_xxxxxxxxxx_xxxxx" \
-H "Content-Type: application/json" \
-d '{"propIds": ["prop-uuid-1", "prop-uuid-2"]}'{
"props": [
{ "propId": "prop-uuid-1", "name": "Wooden Stool", "status": "READY", "ready": true },
{ "propId": "prop-uuid-2", "name": "Fern", "status": "ANALYZING", "ready": false }
],
"allReady": false,
"notFound": []
}Poll every few seconds until allReady is true. GET /props lists the library (filter by status, name, or collectionId) and GET /props/{propId} returns one prop.
Upload decals
Decals are images (logos, labels, graphics) applied to model surfaces. They need no conversion, so they are ready as soon as you confirm.
Create decals and get upload URLs
POST https://api.glossi.io/api/v1/decalscurl -X POST https://api.glossi.io/api/v1/decals \
-H "X-API-Key: glsi_xxxxxxxxxx_xxxxx" \
-H "Content-Type: application/json" \
-d '{"decals": [{ "fileName": "brand_logo.png", "collection": "Logos" }]}'Response (201 Created):
{
"decals": [
{
"decalId": "decal-uuid",
"name": "Brand Logo",
"uploadUrl": "https://s3.amazonaws.com/...",
"uploadKey": "workspaces/.../DECALS/decal-uuid/source.png",
"contentType": "image/png"
}
]
}Accepted formats: png, jpg, jpeg, webp, gif, svg, tif, tiff. Up to 50 per request.
Upload and confirm
The upload must send the returned
contentType. The signed URL is bound to it, so a PUT without that exactContent-Typeheader is refused by storage.
curl -X PUT "https://s3.amazonaws.com/..." \
-H "Content-Type: image/png" \
--data-binary @brand_logo.png
curl -X POST https://api.glossi.io/api/v1/decals/decal-uuid/confirm \
-H "X-API-Key: glsi_xxxxxxxxxx_xxxxx"{ "decalId": "decal-uuid", "status": "READY" }Confirm reads the image's dimensions and marks it ready. POST /decals/status, GET /decals, and GET /decals/{decalId} mirror the prop endpoints.
Import materials
A material is a set of texture images, one per PBR channel: diffuse, normal, roughness, metallic, depth, and opacity. You supply the channels you have; Glossi generates the rest during processing.
Plan a folder import (optional)
If you have a folder of textures named by convention (Wood_Oak_BaseColor.png, Wood_Oak_Normal.png, ...), this endpoint groups them into materials for you. Nothing is uploaded.
curl -X POST https://api.glossi.io/api/v1/materials/plan-import \
-H "X-API-Key: glsi_xxxxxxxxxx_xxxxx" \
-H "Content-Type: application/json" \
-d '{"paths": ["Wood_Oak_BaseColor.png", "Wood_Oak_Normal.png", "Wood_Oak_AO.png", "Leather_ORM.png"]}'{
"materials": [
{
"name": "Wood Oak",
"textures": { "diffuse": "Wood_Oak_BaseColor.png", "normal": "Wood_Oak_Normal.png" }
}
],
"ignored": ["Wood_Oak_AO.png"],
"packed": ["Leather_ORM.png"],
"unmatched": [],
"skipped": [],
"duplicates": []
}ignored lists maps Glossi has no slot for (ambient occlusion, specular, emissive). packed lists combined maps such as ORM, which need to be exported as separate channels. unmatched lists images whose channel could not be told from the name; pass "unmatchedAsDiffuse": true to treat those as single-texture materials.
Create a material and get one upload URL per channel
POST https://api.glossi.io/api/v1/materialscurl -X POST https://api.glossi.io/api/v1/materials \
-H "X-API-Key: glsi_xxxxxxxxxx_xxxxx" \
-H "Content-Type: application/json" \
-d '{
"name": "Wood Oak",
"textures": [
{ "channel": "diffuse", "fileType": "png" },
{ "channel": "normal", "fileType": "png" }
],
"collection": "Woods"
}'Response (201 Created):
{
"materialId": "custom_1757930400000_k3j9x2a",
"name": "Wood Oak",
"collectionId": "collection-uuid",
"uploads": [
{ "channel": "diffuse.png", "uploadUrl": "https://s3.amazonaws.com/..." },
{ "channel": "normal.png", "uploadUrl": "https://s3.amazonaws.com/..." }
],
"uploadedTypes": ["diffuse.png", "normal.png"]
}Texture formats: png, jpg, jpeg, exr. Keep name, uploadedTypes, and collectionId from this response: confirm needs them.
Upload, confirm, and wait
curl -X PUT "https://s3.amazonaws.com/..." --data-binary @Wood_Oak_BaseColor.png
curl -X PUT "https://s3.amazonaws.com/..." --data-binary @Wood_Oak_Normal.png
curl -X POST https://api.glossi.io/api/v1/materials/custom_1757930400000_k3j9x2a/confirm \
-H "X-API-Key: glsi_xxxxxxxxxx_xxxxx" \
-H "Content-Type: application/json" \
-d '{"name": "Wood Oak", "uploadedTypes": ["diffuse.png", "normal.png"], "collectionId": "collection-uuid"}'{ "materialId": "custom_1757930400000_k3j9x2a", "status": "processing" }Processing runs in the background and usually takes one to two minutes. Poll for it:
curl -X POST https://api.glossi.io/api/v1/materials/status \
-H "X-API-Key: glsi_xxxxxxxxxx_xxxxx" \
-H "Content-Type: application/json" \
-d '{"materialIds": ["custom_1757930400000_k3j9x2a"]}'{
"materials": [{ "materialId": "custom_1757930400000_k3j9x2a", "status": "ready" }],
"allReady": true
}status is processing, ready, or failed (with an error field). Once ready, the material can be used in material swaps and by the Studio.
Find materials
GET /materials lists the workspace's materials newest first. Add ?search= for a fuzzy match on name, keywords, and colour (the same search the Studio assistant uses):
curl "https://api.glossi.io/api/v1/materials?search=brushed%20steel" \
-H "X-API-Key: glsi_xxxxxxxxxx_xxxxx"Manage what is in the library
Every kind supports rename and delete, and props, decals, and materials can be moved between collections. The shape is the same across kinds.
Rename or move to a collection
PATCH https://api.glossi.io/api/v1/props/{propId}
PATCH https://api.glossi.io/api/v1/decals/{decalId}
PATCH https://api.glossi.io/api/v1/materials/{materialId}
PATCH https://api.glossi.io/api/v1/models/{modelId}curl -X PATCH https://api.glossi.io/api/v1/props/prop-uuid-1 \
-H "X-API-Key: glsi_xxxxxxxxxx_xxxxx" \
-H "Content-Type: application/json" \
-d '{"name": "Oak Stool", "collection": "Furniture"}'| Field | Description |
|---|---|
name | New library name |
collection | Collection name, created if it does not exist yet. Send null to take the item out of its collection |
collectionId | A collection id instead of a name. Ignored when collection is given |
Models accept name only. The response is the updated item, in the same shape the GET endpoint returns.
Delete
DELETE https://api.glossi.io/api/v1/props/{propId}
DELETE https://api.glossi.io/api/v1/decals/{decalId}
DELETE https://api.glossi.io/api/v1/materials/{materialId}
DELETE https://api.glossi.io/api/v1/models/{modelId}Deletion is permanent and removes the stored files too. Deleting a material also drops it from any surface, colorway, or showroom price list that referenced it. Deleting a model removes it from the projects that use it, so check GET /models/{modelId} first if that matters.
{ "deleted": true, "propId": "prop-uuid-1" }Download a model file
GET https://api.glossi.io/api/v1/models/{modelId}/download?format=glb|usdz|sourceRedirects to a one-hour signed URL for the converted GLB (default), the USDZ derivative, or the original upload. See the Models API for details.
Limits and errors
- Batches: 50 items per create request, 100 ids per status request.
- Signed upload URLs expire after one hour.
- Files: 1 GB per model or prop.
403 STORAGE_LIMIT_REACHEDwhen the workspace's storage allowance is used up (props and models).400 VALIDATION_ERRORfor a malformed request; the message says which item and why.404 NOT_FOUNDwhen an id does not exist in your workspace.
All creation requests accept an Idempotency-Key header, as described in Getting Started.
Control every API step
Create models, confirm uploads, build projects, start renders, inspect status, retry failures, and retrieve outputs through individual endpoints.
Receive signed webhooks
React to supported Glossi events, verify every request, and reconcile state when delivery is missed or duplicated.