GlossiDocs
Open Glossi

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/import
curl -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"
}
FieldRequiredDescription
urlYesPublic http(s) URL. Private network addresses are refused, and every redirect is checked the same way
nameNoLibrary name. Defaults to the file name in the URL
fileTypeNoFile 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/props
curl -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/decals
curl -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 exact Content-Type header 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/materials
curl -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"}'
FieldDescription
nameNew library name
collectionCollection name, created if it does not exist yet. Send null to take the item out of its collection
collectionIdA 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|source

Redirects 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_REACHED when the workspace's storage allowance is used up (props and models).
  • 400 VALIDATION_ERROR for a malformed request; the message says which item and why.
  • 404 NOT_FOUND when an id does not exist in your workspace.

All creation requests accept an Idempotency-Key header, as described in Getting Started.

On this page