> ## Documentation Index
> Fetch the complete documentation index at: https://docs.stackshift.cloud/llms.txt
> Use this file to discover all available pages before exploring further.

# Upload, validate and publish 3D models

> Prepare supported GLB and supplied USDZ files, inspect validation reports, add posters, review the model and launch authorized device AR.

## Goal

Publish a validated model with an accurate poster and controlled viewer/AR behavior.

## Prerequisites

* An owned or licensed GLB or supplied USDZ in a governed Assets bucket.
* Model preparation enabled for the selected space and process permission.
* A separately uploaded approved poster; optional supplied USDZ for the Apple Quick Look path.

## Workflow

<Steps>
  <Step>
    Prepare an embedded-resource GLB within the supported model profile and upload it privately.
  </Step>

  <Step>
    Wait for malware scanning, then validate and optimize the current version.
  </Step>

  <Step>
    Inspect the model report and visually compare the result to the original.
  </Step>

  <Step>
    Create a model publication with a supplied poster and optional validated USDZ companion.
  </Step>

  <Step>
    Review, publish and embed it in a gallery; request AR only on visitor intent.
  </Step>
</Steps>

## 3D viewing, rendering and AR

Interactive 3D lets a visitor orbit and zoom the uploaded model. Product rendering generates a product image, 24-frame spin or turntable video. AR places a supported model into a device environment. These are separate operations with separate inputs and availability.

The gallery uses WebXR/Scene Viewer and Apple Quick Look where supported. Supply a validated USDZ rendition for Quick Look. Review the model’s orientation and real-world scale before publishing it.

## Prepare a supported GLB

* Use GLB version 2 with embedded resources. External URLs and data-URL resources are rejected; package textures into the GLB rather than depending on a remote texture host.
* Source size is at most 100 MiB. The geometry budget is 100,000 triangles and 300,000 vertices, including scene instances. Keep at most one animation and one UV set.
* Supported materials are core PBR, unlit and texture-transform extensions with embedded PNG/JPEG textures. Draco, Meshopt and unsupported extensions are rejected.
* Skins are bounded to 254 joints and four weights per vertex. A model with a small file size can still exceed scene/geometry/texture limits.
* Validated GLB output is capped at 10 MiB, 10 materials and 2,048-pixel textures. Processing deduplicates, prunes and resizes textures; it does not simplify arbitrary excess geometry or provide studio rendering.

## Upload and validate in the dashboard

Choose the correct Assets space and governed bucket, upload the model, and wait for a clean malware scan. Open its inspector’s 3D model section. For GLB select Validate and optimize GLB; for USDZ select Validate USDZ.

If Model preparation is not enabled for this space is shown, ask the space/platform owner about availability. Uploading the file or entering rendering credentials does not enable native preparation. Do not repeatedly upload the same file to work around a disabled capability.

Queued means a model worker has not started it. Processing means validation/optimization is in progress. Ready exposes the report and derived rendition. Failed exposes a reason; correct the input or resolve the reported service condition before retrying. A cancelled/failed attempt can still count toward the configured attempt limit.

## Read and request model processing through the SDK

GET /api/v1/assets/\{assetID}/models returns packages, pilot\_enabled, daily\_jobs and rendering. Match each package’s version\_id to the current source version. During replacement, use the package belonging to the replacement version.

POST to the same route with an empty body requests native model preparation. It uses assets:process, the current If-Match revision and an Idempotency-Key. The returned job\_id/status\_url identifies asynchronous work; request acceptance is not readiness.

```ts theme={null}
const asset = await sdk.assets.get(assetId)
const state = await sdk.assets.dam.models(asset.id)
if (!state.pilot_enabled) throw new Error('Model preparation is unavailable for this space')
const job = await sdk.assets.dam.processModel(asset.id, asset.revision, crypto.randomUUID())
// Later, refresh status; avoid a tight polling loop.
const refreshed = await sdk.assets.dam.models(asset.id)
const current = refreshed.packages.filter(item => item.version_id === asset.current_version_id)
const ready = current.find(item => item.status === 'ready')
```

## Inspect the result before approval

Review the report’s triangles, materials, textures, bytes, animations, units and validator fields when present. Validation passed means structural/media validation passed; it is not AI content moderation, rights approval or visual sign-off.

Compare geometry, materials, textures, orientation and animation with the source. Check a recognizable physical dimension and the supplied poster. A structurally valid file can still depict the wrong product, have incorrect scale or look wrong under device lighting.

## Supply USDZ for Quick Look

Upload USDZ separately and run Validate USDZ. The supported profile is a bounded stored ZIP archive with contained dependencies; links, encryption, traversal and unsupported archive layouts are rejected. Validation uses a static triangle-mesh/preview-surface profile with meter units and Y-up.

The USDZ profile excludes instances, subdivision and animation. It permits at most 100,000 triangles, 300,000 vertices, 10 materials and 16 embedded textures; each texture is at most 2,048 pixels with 16 million pixels across textures.

Select a validated USDZ as a companion to the same product’s GLB publication. Choose matching GLB and USDZ exports of the same product, with consistent shape, textures and scale.

## Add a poster and publish

Upload an image that accurately represents the model. In New publication draft choose the ready model rendition and add its supplied poster. An optional approved image fallback is separate from the model poster. Add the validated USDZ companion only when appropriate.

Use references returned by publicationRenditions for the model and companion assets. Do not use raw original URLs. Complete required metadata, set the allowed channel and usage rights, and follow Submit for review → Approve snapshot → Publish. A ready model package is not automatically public.

Product renders can supply final approved imagery through the rendering workflow. Render preview proofs cannot serve as published posters. See Product rendering for how to create and review final outputs.

## Visitor controls and AR authorization

A gallery initially shows the poster. View in 3D triggers model loading; controls provide orbit, zoom, reset and manual playback for a supported animation. The active item alone mounts, and switching items cleans up its media state.

View in your space requests a fresh server authorization. For a gallery, use resolveGalleryAR with the saved gallery ID and selected member publication. The server checks allow\_ar, current publication/gallery, rights and permissions. Do not reuse a previously returned AR URL as permanent configuration.

Unsupported devices should retain the 3D/image presentation. A granted URL is not DRM: users can retain bytes already downloaded. Withdrawal blocks subsequent authorized requests but cannot erase local copies.

## Troubleshoot models and AR

* Scan pending or failed: complete/recover malware scanning before requesting model processing.
* Unsupported extension or remote dependency: export the supported embedded GLB profile; do not merely rename another format to .glb.
* Geometry/material/output budget exceeded: simplify the source in your modeling tool and upload a new version. The native optimizer is not a general geometry-reduction service.
* Ready package exists only for an old version: prepare the current version and create a new reviewed publication snapshot.
* No poster or no publication rendition: finish processing the companion image/model and select valid returned references.
* AR unavailable: check policy, rights, gallery/publication revision, supplied USDZ where required, and actual device/browser support. Do not assume rendering a turntable fixes AR.

## Go, Python and PHP: validate the current model and track its job

Use the scoped DAM client from the SDK initialization guide. Read the model workspace before admission, obtain the current asset revision through metadataEditor, and retain the caller-generated request key. The response contains job\_id, status and status\_url; store these in your application’s job record.

Poll GET /api/v1/assets/jobs/\{jobID} or refresh models at a modest interval, such as every three seconds while the inspector is open. Stop polling on a terminal job result or when the inspector closes. A successful job must produce a ready package for the intended version\_id before it can become a publication reference. Use publication-renditions to obtain that reference.

For replacement uploads, retain the previous publication until the new model is validated and reviewed. On a failed job, read failure\_reason from its package and correct the input or configuration before retrying. A lost HTTP response should be retried with the same revision and request key.

<CodeGroup>
  ```go Go theme={null}
  package docsexample

  import (
  	"context"
  	"fmt"
  	stackshift "github.com/stackshiftCloud/assets-go"
  )

  func prepareModel(ctx context.Context, dam *stackshift.AssetDAMClient, assetID, requestKey string) (map[string]any, error) {
  	workspace, err := dam.Models(ctx, assetID)
  	if err != nil {
  		return nil, err
  	}
  	if workspace["pilot_enabled"] != true {
  		return nil, fmt.Errorf("model preparation is disabled for this space")
  	}
  	editor, err := dam.MetadataEditor(ctx, assetID)
  	if err != nil {
  		return nil, err
  	}
  	revision, ok := editor["revision"].(float64)
  	if !ok {
  		return nil, fmt.Errorf("missing current asset revision")
  	}
  	return dam.ProcessModel(ctx, assetID, int64(revision), requestKey)
  }
  ```

  ```python Python theme={null}
  def prepare_model(dam, asset_id, request_key):
      workspace = dam.models(asset_id)
      if not workspace["pilot_enabled"]:
          raise RuntimeError("Model preparation is disabled for this space")
      editor = dam.metadata_editor(asset_id)
      return dam.process_model(asset_id, editor["revision"], request_key)
  ```

  ```php PHP theme={null}
  function prepareModel(\StackShift\AssetDAMClient $dam, string $assetId, string $requestKey): array {
      $workspace = $dam->models($assetId);
      if (!$workspace['pilot_enabled']) {
          throw new \RuntimeException('Model preparation is disabled for this space');
      }
      $editor = $dam->metadataEditor($assetId);
      return $dam->processModel($assetId, $editor['revision'], $requestKey);
  }
  ```
</CodeGroup>

## HTTP operations for this workflow

Management requests use Authorization: Bearer with your server-side Assets credential and X-Asset-Space-ID for the selected space. API-key scopes and space/collection permissions both apply. Successful JSON responses use \{success: true, data: ...}; the SDK methods return the unwrapped data. Paths shown outside /api/v1 use their dedicated short-lived credential.

| Operation                                             | Authorization  | Concurrency                                             | Success                              |
| ----------------------------------------------------- | -------------- | ------------------------------------------------------- | ------------------------------------ |
| `GET /api/v1/assets/{assetID}/models`                 | assets:read    | —                                                       | 200                                  |
| `POST /api/v1/assets/{assetID}/models`                | assets:process | Quoted If-Match; Idempotency-Key for preparation/render | 202 preparation/render; 200 estimate |
| `POST /api/v1/assets/publications/{publicationID}/ar` | assets:read    | —                                                       | 200                                  |

For If-Match, quote the revision number, for example If-Match: "7". On 412 assets.revision\_conflict, reload the relevant resource and reconcile the edit before retrying. Use the revision of the resource being changed: asset, collaborator, schema, publication or gallery. A bucket-policy save instead places its current revision in the JSON body.

## Model workspace and job response fields

Model preparation accepts an empty body or \{}. Do not mix preparation with rendering fields. Rendering uses operation=estimate or operation=render on the same route and is documented in Product rendering.

The accepted preparation response contains job\_id, status and status\_url. Read the job through the management API using your normal server credential; status\_url is a relative API path, not a browser asset URL. The model workspace separates prepared packages from rendering.sets.

| Field                                              | Meaning and constraints                                                                                              |
| -------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------- |
| `packages[]`                                       | Prepared model package history. Match version\_id and source\_checksum\_sha256 to the intended source.               |
| `packages[].id / kind`                             | Package UUID; kind identifies the validated glb or usdz representation.                                              |
| `packages[].status`                                | Lifecycle state; use ready only with its validated rendition reference. failure\_reason describes a failed package.  |
| `packages[].rendition_id / output_checksum_sha256` | Immutable output identity when preparation succeeds.                                                                 |
| `packages[].report`                                | Validation/processing report for the model. Inspect dimensions, budgets and unsupported features before publication. |
| `pilot_enabled`                                    | Whether model preparation is enabled for the selected space.                                                         |
| `max_input_bytes / max_web_bytes`                  | Workspace-reported source and web-output byte limits.                                                                |
| `daily_jobs`                                       | Configured daily model-processing job allowance.                                                                     |
| `rendering`                                        | Rendering availability, source binding, allowance, set history and authorized previews; see Product rendering.       |

## Expected result

<Check>
  The published model has a validated immutable rendition, an accurate reviewed poster, and only the AR paths its supplied formats and current policy allow.
</Check>

## Common failures

<Warning>
  * Expecting GLB upload to perform USDZ conversion.
  * Treating structural validation as visual or rights approval.
  * Using a model without a supplied poster.
  * Assuming a 3D desktop preview proves mobile AR support.
</Warning>

## Related guides

<CardGroup cols={2}>
  <Card title="Publications, review and usage rights" href="/assets/publications-review-and-rights">
    Select immutable renditions, capture metadata and rights, submit editorial review, publish by channel, and withdraw delivery.
  </Card>

  <Card title="Create and embed media galleries" href="/assets/media-galleries">
    Arrange published images, video, spins and models with locale, alternate text, approved fallbacks and stable published revisions.
  </Card>

  <Card title="Product rendering: images, spins and turntables" href="/assets/cloudinary-product-rendering">
    Use model-preview controls, estimate rendering units, request proofs or final media, and publish approved immutable outputs.
  </Card>

  <Card title="Typed metadata and bucket governance" href="/assets/metadata-and-bucket-governance">
    Create and publish metadata schemas, bind exact revisions to buckets, validate asset fields, and migrate existing delivery into governance.
  </Card>

  <Card title="Assets SDKs: JavaScript, Go, Python and PHP" href="/assets/sdk-media-workflows">
    Configure space-scoped clients and use native video, governed DAM, model rendering, galleries and CMS capabilities in all four SDKs.
  </Card>
</CardGroup>
