Glossi Docs
Glossi API

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/models

Headers:

HeaderValue
X-API-KeyYour API key
Content-Typeapplication/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 3
  • uploadUrl → You'll upload your file to this URL in Step 2.2

Note: The uploadUrl expires 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:

HeaderValue
Content-Typemodel/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.glb

In Postman:

  1. Set method to PUT
  2. Paste the uploadUrl as the URL
  3. Go to Headers and add Content-Type: model/gltf-binary
  4. Go to Body, select binary, and choose your file
  5. 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}/confirm

Headers:

HeaderValue
X-API-KeyYour API key
Content-Typeapplication/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/status

Headers:

HeaderValue
X-API-KeyYour API key
Content-Typeapplication/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: true when the model can be used in a project
  • allReady: true when ALL models in the request are ready
  • status: 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
done

Note: 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/templates

Headers:

HeaderValue
X-API-KeyYour 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 READY status 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/projects

Headers:

HeaderValue
X-API-KeyYour API key
Content-Typeapplication/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/renders

Headers:

HeaderValue
X-API-KeyYour API key
Content-Typeapplication/json

Body:

{
  "projectIds": ["project-uuid"],
  "settings": {
    "renderBookmarks": true,
    "renderShots": true,
    "renderVariants": true,
    "imageQuality": 1,
    "videoQuality": 1
  }
}

Render Settings Explained

SettingDefaultOptions
renderBookmarkstrueRender all saved camera angles (images)
renderShotstrueRender all video shots
renderVariantstrueRender all material/color variants
imageQuality10=720p, 1=1080p, 2=4K
videoQuality10=Fastest (MP4), 1=Balanced, 2=Best (ProRes)
videoResolution10=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:

HeaderValue
X-API-KeyYour 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: true for videos, false for images

Note: The renders array contains all images and videos generated for this job (bookmarks, shots, and variants).

Job Statuses

StatusMeaning
QUEUEDWaiting to start
RENDERINGCurrently processing
COMPLETEDFinished successfully
FAILEDSomething 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}/retry

Headers:

HeaderValue
X-API-KeyYour 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

EventDescription
model.processedModel upload processing completed successfully
model.failedModel processing failed
project.createdA project was created
job.completeA job workflow completed successfully
job.failedA job workflow failed
render.completeA render completed successfully
render.failedA render failed

Configure Your Webhook

Request:

PUT https://api.glossi.app/api/v1/webhooks

Body:

{
  "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

On this page