Complete Workflow Guide
Beta: The Glossi API is currently in beta. Endpoints, request/response formats, and behavior may change as we iterate. If you run into issues or have feedback, reach out at support@glossi.io.
This guide walks through each API endpoint individually, giving you full control over the model upload, project creation, and rendering process.
Looking for a simpler approach? The Jobs endpoint combines all these steps into a single workflow.
Step 1: Upload a 3D Model
Uploading a model is a two-step process: first you create the model record and get a signed upload URL, then you upload the file directly to our storage.
2.1 Create the Model Record
Request:
POST https://api.glossi.app/api/v1/modelsHeaders:
| Header | Value |
|---|---|
X-API-Key | Your API key |
Content-Type | application/json |
Body:
{
"models": [
{
"name": "My Product",
"fileName": "product.glb",
"fileType": "glb"
}
]
}Example with cURL:
curl -X POST https://api.glossi.app/api/v1/models \
-H "X-API-Key: glsi_xxxxxxxxxx_xxxxx" \
-H "Content-Type: application/json" \
-d '{
"models": [
{
"name": "My Product",
"fileName": "product.glb",
"fileType": "glb"
}
]
}'Response:
{
"models": [
{
"modelId": "abc123-uuid",
"name": "My Product",
"uploadUrl": "https://s3.amazonaws.com/...",
"uploadKey": "workspaces/.../model.glb"
}
]
}Save these values from the response:
modelId→ You'll use this in Steps 2.3 and 3uploadUrl→ You'll upload your file to this URL in Step 2.2
Note: The
uploadUrlexpires after 1 hour. If you're uploading many files, make sure to complete the upload within this time window.
2.2 Upload the File to S3
Now upload your 3D file directly to the signed URL. This request goes directly to S3, not to Glossi's API.
Request:
PUT <uploadUrl from previous response>Headers:
| Header | Value |
|---|---|
Content-Type | model/gltf-binary (for GLB files) |
Body: Your binary file data
Example with cURL:
curl -X PUT "<uploadUrl>" \
-H "Content-Type: model/gltf-binary" \
--data-binary @/path/to/your/model.glbIn Postman:
- Set method to PUT
- Paste the
uploadUrlas the URL - Go to Headers and add
Content-Type: model/gltf-binary - Go to Body, select binary, and choose your file
- Click Send
Note: Don't include your API key for this request - the signed URL already contains authentication.
A successful upload returns an empty response with status 200 OK.
2.3 Confirm the Upload
After uploading to S3, call this endpoint to finalize the model. This updates the file path in our database and marks the model as ready for use in projects.
Request:
POST https://api.glossi.app/api/v1/models/{modelId}/confirmHeaders:
| Header | Value |
|---|---|
X-API-Key | Your API key |
Content-Type | application/json |
Body:
{
"fileType": "glb"
}Example with cURL:
curl -X POST https://api.glossi.app/api/v1/models/abc123-uuid/confirm \
-H "X-API-Key: glsi_xxxxxxxxxx_xxxxx" \
-H "Content-Type: application/json" \
-d '{"fileType": "glb"}'Response:
{
"modelId": "abc123-uuid",
"name": "My Product",
"status": "PENDING",
"filePath": "workspaces/.../model.glb"
}Your model upload is confirmed, but it still needs to be processed before you can use it in a project.
Step 2.4: Wait for Model Processing (Important!)
After confirming the upload, the model goes through processing. You must wait until it's ready before creating a project.
Request:
POST https://api.glossi.app/api/v1/models/statusHeaders:
| Header | Value |
|---|---|
X-API-Key | Your API key |
Content-Type | application/json |
Body:
{
"modelIds": ["abc123-uuid"]
}Example with cURL:
curl -X POST https://api.glossi.app/api/v1/models/status \
-H "X-API-Key: glsi_xxxxxxxxxx_xxxxx" \
-H "Content-Type: application/json" \
-d '{"modelIds": ["abc123-uuid"]}'Response:
{
"models": [
{
"modelId": "abc123-uuid",
"name": "My Product",
"status": "READY",
"ready": true
}
],
"allReady": true,
"notFound": []
}Key fields:
ready:truewhen the model can be used in a projectallReady:truewhen ALL models in the request are readystatus: Current processing status (PENDING,ANALYZING,READY, etc.)
Polling Example
In automation tools like n8n, poll every 5-10 seconds until allReady is true:
# Simple polling loop
while true; do
RESPONSE=$(curl -s -X POST https://api.glossi.app/api/v1/models/status \
-H "X-API-Key: $API_KEY" \
-H "Content-Type: application/json" \
-d '{"modelIds": ["abc123-uuid"]}')
ALL_READY=$(echo $RESPONSE | jq -r '.allReady')
if [ "$ALL_READY" = "true" ]; then
echo "Model ready! Proceeding to create project..."
break
fi
echo "Model still processing..."
sleep 5
doneNote: Models typically take 30 seconds to a few minutes to process, depending on complexity.
Finding Available Templates
Before creating a project, you'll need a template ID. Templates define the lighting, camera angles, and background for your renders. You can list available templates via the API.
Request:
GET https://api.glossi.app/api/v1/templatesHeaders:
| Header | Value |
|---|---|
X-API-Key | Your API key |
Example with cURL:
curl https://api.glossi.app/api/v1/templates \
-H "X-API-Key: glsi_xxxxxxxxxx_xxxxx"Response:
{
"templates": [
{
"templateId": "abc123-template",
"name": "Studio Light",
"description": "Clean studio lighting setup"
},
{
"templateId": "def456-template",
"name": "Outdoor Scene",
"description": "Natural outdoor lighting"
}
]
}Save the templateId for the template you want to use in Step 3.
Filtering Templates
By default, you'll see both public templates (available to everyone) and any custom templates in your workspace. You can filter these:
# Only public templates
curl "https://api.glossi.app/api/v1/templates?internal=false" \
-H "X-API-Key: glsi_xxxxxxxxxx_xxxxx"
# Only your workspace templates
curl "https://api.glossi.app/api/v1/templates?public=false" \
-H "X-API-Key: glsi_xxxxxxxxxx_xxxxx"Step 3: Create a Project
A project combines your 3D model with a template (lighting, camera angles, background). You'll need the modelId you saved from Step 2.1.
Important: Your model must be in
READYstatus before you can create a project with it. See Step 2.4 for how to check model status.
Request:
POST https://api.glossi.app/api/v1/projectsHeaders:
| Header | Value |
|---|---|
X-API-Key | Your API key |
Content-Type | application/json |
Body:
{
"name": "Product Photoshoot",
"modelIds": ["abc123-uuid"],
"templateId": "your-template-uuid"
}Example with cURL:
curl -X POST https://api.glossi.app/api/v1/projects \
-H "X-API-Key: glsi_xxxxxxxxxx_xxxxx" \
-H "Content-Type: application/json" \
-d '{
"name": "Product Photoshoot",
"modelIds": ["abc123-uuid"],
"templateId": "template-uuid"
}'Response:
{
"projects": [
{
"projectId": "project-uuid",
"name": "Product Photoshoot",
"status": "PENDING",
"modelIds": ["abc123-uuid"],
"templateId": "template-uuid"
}
]
}Save the projectId - you'll use it in Step 4 to start a render.
Creating Multiple Projects at Once
If you have multiple models and want a separate project for each:
{
"modelIds": ["model-1-uuid", "model-2-uuid", "model-3-uuid"],
"templateId": "template-uuid",
"createPerModel": true
}This creates 3 projects, one for each model.
Step 4: Start a Render
Now you can render your project to generate images and videos. Use the projectId you saved from Step 3.
Request:
POST https://api.glossi.app/api/v1/rendersHeaders:
| Header | Value |
|---|---|
X-API-Key | Your API key |
Content-Type | application/json |
Body:
{
"projectIds": ["project-uuid"],
"settings": {
"renderBookmarks": true,
"renderShots": true,
"renderVariants": true,
"imageQuality": 1,
"videoQuality": 1
}
}Render Settings Explained
| Setting | Default | Options |
|---|---|---|
renderBookmarks | true | Render all saved camera angles (images) |
renderShots | true | Render all video shots |
renderVariants | true | Render all material/color variants |
imageQuality | 1 | 0=720p, 1=1080p, 2=4K |
videoQuality | 1 | 0=Fastest (MP4), 1=Balanced, 2=Best (ProRes) |
videoResolution | 1 | 0=720p, 1=1080p, 2=4K |
Example - Render images only at 4K:
curl -X POST https://api.glossi.app/api/v1/renders \
-H "X-API-Key: glsi_xxxxxxxxxx_xxxxx" \
-H "Content-Type: application/json" \
-d '{
"projectIds": ["project-uuid"],
"settings": {
"renderBookmarks": true,
"renderShots": false,
"imageQuality": 2
}
}'Response:
{
"jobs": [
{
"jobId": "job-uuid",
"status": "QUEUED",
"projectId": "project-uuid"
}
],
"totalProjects": 1
}Save the jobId - you'll use it in Step 5 to check the render status.
Rendering Multiple Projects
You can render multiple projects in a single request:
{
"projectIds": ["project-1", "project-2", "project-3"],
"settings": {
"renderBookmarks": true,
"imageQuality": 1
}
}Step 5: Check Render Status
Renders take time to complete. Use the jobId from Step 4 to poll for progress.
Request:
GET https://api.glossi.app/api/v1/renders/{jobId}Headers:
| Header | Value |
|---|---|
X-API-Key | Your API key |
Example with cURL:
curl https://api.glossi.app/api/v1/renders/job-uuid \
-H "X-API-Key: glsi_xxxxxxxxxx_xxxxx"Response (in progress):
{
"jobId": "job-uuid",
"status": "RENDERING",
"projectId": "project-uuid"
}Response (complete):
{
"jobId": "job-uuid",
"status": "COMPLETED",
"projectId": "project-uuid",
"renders": [
{
"id": "render-uuid-1",
"name": "Front View - Default",
"filePath": "workspaces/.../render.png",
"fileType": "PNG",
"isVideo": false
},
{
"id": "render-uuid-2",
"name": "360 Spin - Default",
"filePath": "workspaces/.../video.mp4",
"fileType": "MP4",
"isVideo": true
}
]
}Key fields in renders:
name: Display name of the render (e.g., "Front View - Oak")filePath: S3 path to the file (use this to copy/download the render)fileType: Format of the file (PNG,MP4,PRORES, etc.)isVideo:truefor videos,falsefor images
Note: The
rendersarray contains all images and videos generated for this job (bookmarks, shots, and variants).
Job Statuses
| Status | Meaning |
|---|---|
QUEUED | Waiting to start |
RENDERING | Currently processing |
COMPLETED | Finished successfully |
FAILED | Something went wrong (check errorMessage) |
Retrying Failed Renders
If a render fails, you can retry it:
Request:
POST https://api.glossi.app/api/v1/renders/{jobId}/retryHeaders:
| Header | Value |
|---|---|
X-API-Key | Your API key |
Example with cURL:
curl -X POST https://api.glossi.app/api/v1/renders/job-uuid/retry \
-H "X-API-Key: glsi_xxxxxxxxxx_xxxxx"Response:
{
"jobId": "job-uuid",
"status": "QUEUED",
"projectId": "project-uuid",
"batchId": "new-batch-uuid"
}The job will be re-queued and you can poll for status as before. Note that only jobs with status FAILED can be retried.
Step 6: Set Up Webhooks (Optional)
Instead of polling, you can receive notifications when important events occur.
Full documentation: See the Webhooks Guide for complete details on all events, payload formats, and signature verification.
Available Events
| Event | Description |
|---|---|
model.processed | Model upload processing completed successfully |
model.failed | Model processing failed |
project.created | A project was created |
job.complete | A job workflow completed successfully |
job.failed | A job workflow failed |
render.complete | A render completed successfully |
render.failed | A render failed |
Configure Your Webhook
Request:
PUT https://api.glossi.app/api/v1/webhooksBody:
{
"url": "https://your-app.com/webhooks/glossi",
"events": [
"model.processed",
"model.failed",
"project.created",
"job.complete",
"job.failed",
"render.complete",
"render.failed"
],
"enabled": true
}Response:
{
"id": "webhook-uuid",
"url": "https://your-app.com/webhooks/glossi",
"secret": "your-webhook-secret",
"events": ["model.processed", "job.complete", "render.complete", ...],
"enabled": true
}Save the secret - you'll use it to verify webhook signatures.
Webhook Payloads
When a model finishes processing:
{
"event": "model.processed",
"timestamp": "2025-01-15T10:30:00.000Z",
"data": {
"modelId": "model-uuid",
"name": "Chair Model",
"status": "READY",
"glbFilePath": "https://s3.../file.glb",
"thumbnailUrl": "https://s3.../file.jpg"
}
}When a job completes:
{
"event": "job.complete",
"timestamp": "2025-01-15T10:30:00.000Z",
"data": {
"jobId": "job-uuid",
"status": "COMPLETE",
"results": [
{
"model": { "id": "model-uuid", "name": "Chair" },
"project": { "id": "project-uuid", "name": "Chair Project" }
}
]
}
}When a render completes:
{
"event": "render.complete",
"timestamp": "2025-01-15T10:30:00.000Z",
"data": {
"jobId": "render-job-uuid",
"status": "COMPLETED",
"projectId": "project-uuid",
"renderIds": ["render-uuid-1", "render-uuid-2"]
}
}Verify Webhook Signatures
Always verify the X-Glossi-Signature header to ensure the request came from Glossi:
const crypto = require("crypto")
function verifyWebhook(payload, signature, secret) {
const expected = crypto.createHmac("sha256", secret).update(JSON.stringify(payload)).digest("hex")
return crypto.timingSafeEqual(Buffer.from(signature), Buffer.from(expected))
}Next Steps
- Webhooks Guide - Full webhook documentation
- Simple Workflow - Streamlined Jobs endpoint
- Getting Started - API key setup and overview