This is 2026.9 preview documentation. Coverage here is incremental: a page exists only where
2026.9 differs or is newly documented.
Receive2 → Flatten. In 2026.9 that
receive is obsolete. The new path is Receive3, which returns a disposable Model with columnar
properties and typed relations. Dates, compatibility mode, and who must act are on
Data model migration for developers. The object-model
change itself is on Object model in 2026.9.
Prefer
Receive3 for new scripts. Receive2 stays callable on legacy object-graph versions.What changes for a script
Update packages
Bump every Speckle NuGet reference to the same 2026.9 version, then removeSpeckle.Objects.
Namespaces stay Speckle.Objects.*, so usings do not change.
Speckle.Objects package reference from the project file. Pin an explicit 2026.9
build rather than a floating range.
You can drop typeof(Speckle.Objects.Geometry.Point).Assembly from AddSpeckleSdk unless you
register your own Base types. Geometry types now live in Speckle.Sdk.
Load a model
Prior to 2026.9, you resolvereferencedObject and call Receive2. In 2026.9, Receive2 is marked
[Obsolete]. Receive3 takes the same account and ids and returns a disposable Model. Wrap that
Model in using: it owns the downloaded bundle files on disk until you dispose it.
Auth, bootstrap, and version lookup stay on scripts and notebooks.
The snippets below assume account, client, projectId, modelId, and latest are already in scope.
- Prior to 2026.9 (Receive2)
- 2026.9 (Receive3)
Prior to 2026.9
Count and filter objects
Prior to 2026.9, you walk aBase tree. In 2026.9, objects are a flat list. Properties are path-keyed
("category", "Constraints.Base Offset"). Relations are accessors, not Proxy lists.
- Prior to 2026.9
- 2026.9
Prior to 2026.9
model.ObjectByApplicationId(id). applicationId is the only identity a
bundle object has. Do not treat Base.id as a content hash on bundle-only versions.
Replace property walks
Prior to 2026.9, nested parameters are dictionaries you walk:obj.properties["x"] then ["y"]. In
2026.9 those paths are flat. PropertyView is the type that replaces that walk.
PropertyView
PropertyView (Speckle.Sdk.Pipelines.Receive.Artifacts) is a read-only view over one object’s
property rows. Keys are dotted paths ("Constraints.Base Offset"), not nested dictionaries. It does
not allocate until you enumerate it. ModelObject.Properties is this view; cast to PropertyView
when you need the helpers below.
GetString/GetDouble/GetBool: typed lookup. Null if the path is missing or the value is another type.Under("Constraints"): the subtree under that prefix, with the prefix stripped. No allocation.- Indexer /
TryGetValue: untyped lookup, same paths asGetString. ToNested(): the old nested-dictionary tree. Allocates. Use only when a caller still requires that shape.
ModelObject.GetString, GetDouble, and GetBool do the same typed lookup with instance, then
type, then root-scalar precedence. Prefer those for a single path. Use PropertyView.Under when you
need a group.
- Prior to 2026.9
- 2026.9
Prior to 2026.9
Replace Proxy walks
Prior to 2026.9, grouping by level or material means indexingapplicationIds and resolving proxy objects
lists. In 2026.9 those links are typed relations. See
Relations in 2026.9 for the names.
- Prior to 2026.9
- 2026.9
Prior to 2026.9
elements tree or Proxy objects list on 2026.9 data is expected. Do not unpack
Proxies to rebuild containment.
What Receive2 still does
Receive2 remains callable. It is obsolete for a reason.
- Legacy object-graph versions: behaviour is unchanged. You still pass
referencedObjectas a content hash. - Bundle-only versions:
referencedObjectis a bundle reference (bundle.<projectId>.<modelId>.<versionId>). A 2026.9 SDK dispatches on that prefix and returns a best-effortBasetree (DataObject idiom,version = 4on the root). That projection does not scale to the model sizes the bundle format is built for, and it is not a lossless round trip. - Older SDKs: fetching that
referencedObjectfrom the objects API returns 404 with upgrade guidance. Upgrade Speckle.Sdk rather than parsing the 404 body.
Receive cannot load bundle-only versions. It throws if you pass a bundle
reference.
Publish from a script
Most analysis scripts only receive. If you currently callSend2 then Version.Create, the
2026.9 replacement is Send3 with a BundleBuilder. Send2 stays accepted and starts emitting
deprecation warnings. There is no removal date.
Send3 returns a reserved version id immediately. Queries, the version URL, and
version_created webhooks fire when ingestion completes. Poll for the version, or watch the
project’s model ingestions, if you need to follow up in the same process.
FAQ
Do I have to rewrite a Receive2 script on day one?
Do I have to rewrite a Receive2 script on day one?
Upgrade Speckle.Sdk first so versions from a 2026.9 connector do not 404. Versions from older
connectors keep working on
Receive2. Rewrite to Receive3 when you need relations, columnar
property lookups, or models that are too large to materialize as a Base tree.Why does Receive3 return Model instead of Base?
Why does Receive3 return Model instead of Base?
Model is the bundle itself: objects, path-keyed properties, and relation accessors, with
geometry parsed only when you ask. A Base tree inflates every object and mesh into managed
objects. That is why Receive2 is obsolete for the new format.What happens if I forget to dispose Model?
What happens if I forget to dispose Model?
Downloaded parquet files stay under a scratch directory until
Dispose runs. Always wrap the
result in using. Objects and already-loaded geometry stay in memory after dispose; geometry
you have not touched yet cannot be read afterwards.Can I keep using ITransport?
Can I keep using ITransport?
Yes for hash-era data, until that path is retired. It will never carry bundles. Move
server-facing scripts to
Receive3. See the send and receive
paths page for the transport story.