version.referencedObject, reads units off the root object, or walks
down from it, that script breaks on a bundle version: one whose referencedObject starts with
bundle.. Bundle data has no root object. The jobs the root object used to do are split across
four places: the version record on the server, the model ingestion that publishes it, a one-row
provenance stamp inside the bundle, and model-scoped properties. This page says where each piece
went and what a script reads instead.
In versions published before 2026.9, as the Data Schema
describes, a version points at one object: version.referencedObject is the id of the Root
Collection, historically called the commit
object. That object is the entry point for every traversal, and it carries the model-wide facts a
script reads first: units, a name, the nested elements tree,
Proxies, and Info
such as views and the reference point transform. The version record beside it carries the message,
source application, author, and creation date. Versions and the root
object covers that split in full.
For how objects relate to each other, see Relations. For
the two-store picture, see Object model.
What the root object carried, and where it lives now
Two rows need more detail because scripts depend on them.
The bundle reference is a pointer, not a hash. On a bundle-only version,
referencedObject
names the version, not its content. Resolve the version through the project and version id you
already hold, then read its data with receive3 / Receive3. The embedded model id is the model
at creation time and goes stale if the version is later moved.
Units are per object, not per version. A bundle can carry more than one unit. The SDK’s
Model.units is the first non-empty unit it finds, which is the builder’s default on data you
published yourself. When precision matters, read the object’s own units property.
How a publish creates a version
send3 / Send3 runs all of this for you. Knowing the sequence explains why the version is not
queryable the moment the call returns, and where each piece of metadata is set.
1
Open a model ingestion
The SDK creates an ingestion on the model, carrying the producer slug and version from your
bundle builder and a progress message from your send options. The outcome is an ingestion with a
reserved version id.
2
Build the bundle
The builder writes its parquet files, named by the reserved version id, and stamps the
meta
row with the spec version and producer. The outcome is a complete bundle on local disk.3
Upload the files
Each file goes to storage through a presigned upload. The outcome is every file stored under the
version id.
4
Complete the upload
The SDK completes the ingestion with the bundle reference and the object count. The outcome is
the server creating the version in one step, with
referencedObject set to the bundle reference
and schemaVersion set to 3.5
Wait for the version
send3 returns the reserved id immediately. Poll the ingestion, or call WaitForVersion in
.NET, before you query, link, or receive it. The outcome is a version that answers queries and
arrives as CREATED on the projectVersionsUpdated subscription.account, project_id / projectId, and model_id / modelId are already in scope.
- Python
- .NET
version.create / Version.Create publish object graphs, a deprecated path that new work does
not use. They too return a reserved id; see Publish through model
ingestions.Read version metadata from a script
Read the version record for identity and provenance: nullablemessage, sourceApplication,
authorUser, createdAt, schemaVersion, referencedObject, and the optional summary. A
summary contains facts the producer computed during conversion, grouped into namespaces such as
modelHealth; it is not a replacement for model or object properties. This is the same query as
for any other version.
Read model-wide facts from the received Model, not from a root object. units gives the
default unit. properties holds the model-scoped rows: the placement record
(modelPlacement.transform, modelPlacement.units, modelPlacement.source,
modelPlacement.appliedToGeometry) and any document settings or project information the connector
published. camera_views holds saved cameras.
FAQ
Is there a root object I can start traversing from?
Is there a root object I can start traversing from?
No. Start from the version and receive it as a
Model, then key objects by applicationId and
follow relations. A container with subtype Model exists as the IN_MODEL target, but it is a
grouping tier for federated source files, not a root, and it carries only a name.Why is Version.schemaVersion 3 when the bundle says schema_version 1.x?
Why is Version.schemaVersion 3 when the bundle says schema_version 1.x?
They are different numbers.
Version.schemaVersion is the server’s storage-shape flag: 3
means the version is served as a bundle, null means it is an object graph.
meta.schema_version inside the bundle is the semver of the bundle format the producer wrote
against. Neither moves when the other does.What happens if my script fetches referencedObject from the objects endpoint?
What happens if my script fetches referencedObject from the objects endpoint?
It gets a 404 with a
BUNDLE_REFERENCE_NOT_FOUND body. That is the contract, not empty data.
Dispatch on the bundle. prefix and receive the version through the SDK instead.Where do I put model-wide facts when I publish?
Where do I put model-wide facts when I publish?
Add them as model-scoped properties on the bundle builder, not on an object. That is the home
for document settings, project information, and the placement record (
modelPlacement.*). Units
go on the builder, or on an individual object when it differs from the default.