Complete Workflow

1

Upload a 3D Model

Uploading a model is a two-step process: create the model record to get a signed upload URL, then upload the file directly to storage.

Create the Model Record

Request:

POST https://api.glossi.app/api/v1/models

Headers:

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 → used in later steps

  • uploadUrl → upload your file to this URL

circle-info

The uploadUrl expires after 1 hour. If uploading many files, complete the upload within this time window.

Upload the File to S3

Upload your 3D file directly to the signed URL (this request goes to S3, not 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.glb

In Postman:

  1. Set method to PUT

  2. Paste the uploadUrl as the URL

  3. Add header Content-Type: model/gltf-binary

  4. Body → binary → choose file → Send

circle-exclamation

A successful upload returns an empty response with status 200 OK.

Confirm the Upload

After uploading to S3, finalize the model so the file path is saved and the model is marked ready for processing.

Request:

POST https://api.glossi.app/api/v1/models/{modelId}/confirm

Headers:

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

The upload is confirmed; the model will now be processed before it can be used in a project.

2

Wait for Model Processing (Important!)

After confirming the upload, poll the model status until it's ready.

Request:

POST https://api.glossi.app/api/v1/models/status

Headers:

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: true when the model can be used in a project

  • allReady: true when ALL models in the request are ready

  • status: processing status (PENDING, ANALYZING, READY, etc.)

Polling example (bash):

# 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
circle-info

Models typically take 30 seconds to a few minutes to process, depending on complexity.

3

Finding Available Templates

Templates define lighting, camera angles, and background for renders.

Request:

GET https://api.glossi.app/api/v1/templates

Headers:

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 when creating a project.

Filtering examples:

# 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"
4

Create a Project

A project combines your 3D model with a template (lighting, camera angles, background). Ensure your model is READY before creating a project.

Request:

POST https://api.glossi.app/api/v1/projects

Headers:

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 to start a render.

Creating multiple projects at once:

{
  "modelIds": ["model-1-uuid", "model-2-uuid", "model-3-uuid"],
  "templateId": "template-uuid",
  "createPerModel": true
}

This creates one project per model.

5

Start a Render

Use the projectId from the previous step to generate images/videos.

Request:

POST https://api.glossi.app/api/v1/renders

Headers:

Header
Value

X-API-Key

Your API key

Content-Type

application/json

Body example:

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

Response:

{
  "jobs": [
    {
      "jobId": "job-uuid",
      "status": "QUEUED",
      "projectId": "project-uuid"
    }
  ],
  "totalProjects": 1
}

Save the jobId — you'll use it to check render status.

Rendering multiple projects:

{
  "projectIds": ["project-1", "project-2", "project-3"],
  "settings": {
    "renderBookmarks": true,
    "imageQuality": 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
    }
  }'
6

Check Render Status

Poll the job status with the jobId.

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

  • filePath: S3 path to the file (use to copy/download)

  • fileType: Format of the file (PNG, MP4, PRORES, etc.)

  • isVideo: true for videos, false for images

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

Job Statuses

Status
Meaning

QUEUED

Waiting to start

RENDERING

Currently processing

COMPLETED

Finished successfully

FAILED

Something went wrong (check errorMessage)

Retrying Failed Renders

Request:

POST https://api.glossi.app/api/v1/renders/{jobId}/retry

Headers:

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

Only jobs with status FAILED can be retried.

7

Set Up Webhooks (Optional)

Instead of polling, receive notifications for important events.

Full documentation: See the Webhooks Guide at ./API_WEBHOOKS.md

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

chevron-rightModel processed payloadhashtag
chevron-rightJob complete payloadhashtag
chevron-rightRender complete payloadhashtag

Verify Webhook Signatures

Always verify the X-Glossi-Signature header to ensure the request originates 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))
}
circle-info

Next steps:

  • Webhooks Guide: ./API_WEBHOOKS.md

  • Simple Workflow: ./API_SIMPLE_WORKFLOW.md

  • Getting Started: ./API_GETTING_STARTED.md

Was this helpful?