Receive3: versions published by a 2026.9 connector need that build, and their full data shape only comes through Receive3. Speckle does not guarantee that older Speckle.Sdk builds, or Receive2, keep working against current servers. This page shows each change side by side so you can judge how much of your script moves.
The old path is PAT → bootstrap → Receive2 → Flatten. The 2026.9 path is PAT → bootstrap → Receive3, which returns a disposable Model with columnar properties and typed relations. For the data model itself, see Object model. For dates and who must act, see Data model migration for developers.
What changes for a script
Update packages
Update every Speckle NuGet reference to the same 2026.9 version, then removeSpeckle.Objects. 2026.9.0-beta.7 is the current 2026.9 build on NuGet; a plain dotnet add package Speckle.Sdk still installs 2026.8, which has no Receive3. A later stable 2026.9.0 replaces the beta pin; the calls on this page do not change.
Speckle.Objects package reference. Namespaces stay Speckle.Objects.*, so your using lines do not change.
The bootstrap does not change. typeof(Speckle.Objects.Geometry.Point).Assembly in AddSpeckleSdk still compiles, because geometry types now live in the Speckle.Sdk assembly. You only need to pass an assembly when you register your own Base types.
Load a model
Receive2 is marked [Obsolete] in 2026.9. 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 as on Automate with scripts. 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
Receive3 reads the version’s bundle. A version published before 2026.9 that the server has not
converted has no bundle, and Receive3 throws a SpeckleException. Load that version with
Receive2.Count and filter objects
Before 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 a 2026.9 version.
Replace property walks
Before 2026.9, nested parameters are dictionaries you walk:obj.properties["x"] then ["y"]. In 2026.9 those paths are flat, and PropertyView replaces the walk.
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 it only when a caller still needs that shape.
ModelObject.GetString, GetDouble, and GetBool look up instance properties first, then type properties, then root scalars. 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
Before 2026.9, grouping by level or material meant indexingapplicationIds and resolving proxy
objects lists. In 2026.9, use the typed relation accessors directly. See
Relations for the names.
2026.9
elements tree and no proxy objects lists. Do not unpack proxies to rebuild containment; read the relation accessors instead.
Read versions published before 2026.9
Receive2 is obsolete. Keep it only to read versions published before 2026.9 that have no bundle; use Receive3 for everything else.
- Versions published before 2026.9: pass
referencedObjectas a content hash and get the object graph back. - Versions published in 2026.9:
referencedObjectis a bundle reference (bundle.<projectId>.<modelId>.<versionId>). A 2026.9 SDK recognizes the 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. Do not build new work on it. - Older SDKs: fetching a bundle reference from the objects API returns 404 with upgrade guidance. Update Speckle.Sdk rather than parsing the 404 body.
Receive cannot load 2026.9 versions. It throws if you pass a bundle reference.
Receive, derive new data, then send to a new version remains supported.
Publish from a script
Most analysis scripts only receive. If your script callsSend2 then Version.Create, move it to Send3 with a BundleBuilder. Send2 is obsolete, and Speckle does not guarantee it for new work; see Publish through model ingestions.
Send3 returns a SendResult with a reserved version id as soon as the upload finishes. The version appears in queries and at its URL, and fires webhooks, when the server finishes processing. Call WaitForVersion when the same script needs the version to exist.
2026.9
FAQ
Can I keep my Receive2 script as it is?
Can I keep my Receive2 script as it is?
No, not any longer. Update Speckle.Sdk to 2026.9.0-beta.7 and load versions with
Receive3.
Older Speckle.Sdk builds get a 404 on versions from a 2026.9 connector, and Speckle does not
guarantee they keep working against current servers. Keep Receive2 only to read versions
published before 2026.9 that have no bundle.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, which 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?
The downloaded parquet files stay in a scratch directory until
Dispose runs. Always wrap the
result in using. Objects and geometry you already read stay in memory after dispose; geometry
you have not touched cannot be read afterwards.Can I keep using ITransport?
Can I keep using ITransport?
Only to read versions published before 2026.9. Transports never carry bundles, so load
everything else with
Receive3. See Load and publish model
data.