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

> ## Agent Instructions
> These docs describe Speckle as it works today, including everything released in 2026.9. Treat page content as current unless the page or section says it applies only to versions published before 2026.9.
> Content scoped to versions published before 2026.9 (the object graph and root object, Proxies, Receive2, operations.receive, object.children) applies only to model versions in that earlier data format. For versions published in 2026.9, answer from the Object model pages and the SDK migration guides.
> The What's new pages summarise what changed in 2026.9 and link to the page that documents each change. Answer from the linked page rather than from the summary. Legacy (v2) connectors are retired; send questions about them to the community help forum.
> Match guidance to the customer's deployment, model data format, connector, plan and permissions. Self-hosted servers on a release before 2026.9 follow Data model migration for developers. If an unknown version or data format changes the answer, ask one focused question; do not infer the deployment version from the date alone.

# Use model properties in Power Automate, Zapier, or n8n

> Get every element property of a Speckle model version as JSON in a Power Automate, Zapier, or n8n flow, by calling a small web function that reads the version's bundle.

Use this guide if you build automations in Power Automate, Zapier, or n8n and want the
properties of a Speckle model in your flow: every element's type, name, dimensions, and parameters,
as rows you can filter, count, and send on.

Models uploaded to Speckle since the 2026.9 release are stored as **bundles**: Parquet files that
low-code tools cannot read. The properties export your flow may already call (`eav/query`) serves
only versions in the earlier format. This guide adds one small function between your flow and
Speckle. Your flow sends it a project, model, and version id; it returns the version's properties
as JSON, in the same columns as the properties export.

> [!NOTE]
>
> Someone has to set the function up once: a developer, or anyone comfortable deploying a small
> piece of code. Where it runs depends on the tools you already use; see [Choose where it
> runs](#choose-where-it-runs). After that, building and changing the flow is all low-code.

## How it works

1. Your flow's HTTP action POSTs `{"projectId", "modelId", "versionId"}` to the function's URL.
2. The function asks Speckle for the version's files and reads the property files directly. Your
   Speckle token stays in the function's settings, never in the flow.
3. Your flow gets one row per property of every element, as JSON it can parse and filter.

Each row looks like this:

```json theme={null}
{
  "object_id": "0Jgy8odqv9EeWIex0hC4$r",
  "path": "ifcType",
  "value_text": "IfcSpace",
  "value_num": null,
  "type": "string",
  "units": null,
  "internal_definition_name": null
}
```

| Field | Holds |
| - | - |
| `object_id` | The element's id from the source file (an IFC GlobalId, a Revit id) |
| `path` | The property name, such as `ifcType` or `Dimensions.Area` |
| `value_text` | The value as text, on every row |
| `value_num` | The value as a number, on numeric rows |
| `type` | `string`, `number`, or `boolean` |
| `units` | The unit, where the source gave one |
| `internal_definition_name` | The property's internal definition name, when available |

Type properties (Revit type parameters, IFC type properties) are included, so each element carries
its type's properties too.

## Prerequisites

* A Speckle personal access token with the `streams:read` scope, from a user who can read the
  project ([Building with PATs](https://docs.speckle.systems/developers/authentication/pats.md))
* Somewhere to run the function; see [Choose where it runs](#choose-where-it-runs)
* Power Automate with the premium **HTTP** action, Zapier with **Webhooks by Zapier**, or n8n

> [!NOTE]
>
> This works on Speckle Cloud and Speckle Enterprise Server 2026.9 and later. The open-source
> Speckle Server has no bundles: there, keep using the [properties
> export](https://docs.speckle.systems/developers/api/rest.md#properties-export).

## Find your IDs

Open the model version in Speckle and read the IDs from the address bar:

```
https://app.speckle.systems/projects/{projectId}/models/{modelId}@{versionId}
```

If the address has no `@{versionId}`, the viewer is showing the latest version. Open the specific
version you want so its id appears.

## Choose where it runs

The function only has to be reachable over HTTPS and able to run Python, Node.js, or .NET. Pick
the host your organisation already uses:

| You build flows in | Simplest place for the function |
| - | - |
| Power Automate (cloud) | [Azure Functions](#on-azure-functions): it sits with your other Microsoft services, and the sample deploys as it is. |
| Power Automate Desktop | No function: a [PowerShell script on the same machine](#on-power-automate-desktop) writes the properties to a CSV file. |
| Zapier or n8n Cloud | [AWS Lambda](#on-aws-lambda), which the sample also supports, or any serverless host you already have, such as Google Cloud Run functions ([adapt the sample](#on-another-host)). |
| Self-hosted n8n | No separate function: run the query in a **Code** node, if your n8n admin enables external modules and installs `@duckdb/node-api`. The TypeScript sample's `src/properties.ts` is the code to start from. |

If your flow feeds a Power BI or Excel report rather than an automation, you may not need a function
at all: Power Query can load the bundle's Parquet files directly.

## As the person who deploys the function

You do this once. The function is a ready-made sample in Python, TypeScript, and C#:
[examples/bundle-properties-function](https://github.com/specklesystems/speckle-docs-new/tree/main/examples/bundle-properties-function).
Pick the language your team maintains; they behave the same.

### On Azure Functions

Get just the sample folder, then publish one language folder to a Function App, for example with
the Azure Functions Core Tools:

```bash theme={null}
git clone --filter=blob:none --sparse --depth 1 \
  https://github.com/specklesystems/speckle-docs-new.git
cd speckle-docs-new
git sparse-checkout set examples/bundle-properties-function
cd examples/bundle-properties-function/python
func azure functionapp publish YOUR_FUNCTION_APP
```

For Python, create the Function App on Python 3.12. The sample's README covers running it locally
first, and the TypeScript and C# folders.

Then add the token. In the Azure portal, open the Function App, go to **Settings → Environment
variables**, and add:

| Name | Value |
| - | - |
| `SPECKLE_TOKEN` | The personal access token |
| `SPECKLE_URL` | Only for your own server: its address |

Then open the `properties` function, copy its **function URL**, and give it to the flow builder. The
URL ends in `?code=...`, the key that lets a flow call it, so share it as a secret.

### On AWS Lambda

The Python and TypeScript folders include a Lambda handler for a function URL. Package the folder
for Linux, create the function on Python 3.12 or Node.js 22, and set `SPECKLE_TOKEN` and a
`FUNCTION_KEY` of your choosing as environment variables. The sample's README has the exact package
commands, handler names, and memory settings.

Create a function URL with auth type `NONE`: the handler only answers requests that carry the
`FUNCTION_KEY` in an `x-api-key` header. Give the flow builder the URL and the key, and share both as
secrets.

### On another host

Each sample keeps the query apart from the Azure wrapper: `python/properties.py`,
`typescript/src/properties.ts`, and `csharp/BundleProperties.cs` run anywhere. On another host,
copy that file and write the host's own HTTP handler around it: read the three IDs from the request
body, fetch the version's file list from Speckle with the token, pass the files to the query, and
return the rows as JSON. The Azure and Lambda handlers in the same folder are 30-line models to follow.

Keep the token in the host's secret settings as `SPECKLE_TOKEN`, and protect the URL with the
host's own key or authentication, since anyone with it can read the model's properties.

## As the flow builder

You need the function URL from whoever deployed it, and the three IDs. On AWS Lambda you also need
the key, which every request sends as an `x-api-key` header.

> [tab] Power Automate
>
> 1. Add an **HTTP** action. Set **Method** to `POST`, **URI** to the function URL, and a header
>    `Content-Type: application/json`. On AWS Lambda, add the header `x-api-key` too.
> 2. Set **Body** to the IDs, as shown below.
> 3. Add **Parse JSON** with **Content** set to the HTTP action's **Body**. Generate the schema
>    from the example row above, wrapped in `[ ]`.
> 4. Add **Filter array** on the parsed body. For example, `path` equals `ifcType` and
>    `value_text` equals `IfcDoor` gives one row per door. Use their `object_id` values in a
>    second **Filter array** to pick out the rest of their properties.
>
> ```json Body theme={null}
> { "projectId": "PROJECT_ID", "modelId": "MODEL_ID", "versionId": "VERSION_ID" }
> ```

> [tab] Zapier
>
> 1. Add a **Webhooks by Zapier** action with the **POST** event. On AWS Lambda, add `x-api-key`
>    under **Headers**.
> 2. Set **URL** to the function URL and **Payload Type** to `json`.
> 3. Under **Data**, add `projectId`, `modelId`, and `versionId`.
> 4. Filter the returned rows in a **Filter** or **Code by Zapier** step.

> [tab] n8n
>
> 1. Add an **HTTP Request** node with **Method** `POST` and **URL** the function URL. On AWS
>    Lambda, turn on **Send Headers** and add `x-api-key`.
> 2. Turn on **Send Body**, set **Body Content Type** to `JSON`, and add the three IDs as fields.
> 3. Each returned row becomes an item; filter them with a **Filter** node.

You should see one row per property of every element in the version, as in the example above.

## On Power Automate Desktop

A desktop flow runs on a Windows machine, so it needs no function: a PowerShell script on that
machine fetches the version's files, runs the query, and writes the properties to a CSV file the
flow reads.

Set up the machine once:

1. Download the DuckDB command-line tool for Windows from [duckdb.org](https://duckdb.org/install/)
   and unzip `duckdb.exe` to a folder such as `C:\speckle`.
2. Save
   [Get-BundleProperties.ps1](https://raw.githubusercontent.com/specklesystems/speckle-docs-new/refs/heads/main/examples/bundle-properties-function/powershell/Get-BundleProperties.ps1)
   and
   [query.sql](https://raw.githubusercontent.com/specklesystems/speckle-docs-new/refs/heads/main/examples/bundle-properties-function/query.sql)
   to the same folder.
3. Store the token for the Windows account that runs the flow, then restart Power Automate Desktop
   so it sees the new variable:

   ```powershell theme={null}
   setx SPECKLE_TOKEN "YOUR_TOKEN"
   ```

Then build the flow:

1. Add **Run DOS command** with the command below, using your IDs and folder.
2. Add **Read from CSV file** on the output file, with **First line contains column names** turned
   on. Each property becomes a row of a data table.
3. Filter the rows with **Filter data table**. For example, `path` equals `ifcType` and
   `value_text` equals `IfcDoor` gives one row per door.

```text Command theme={null}
powershell -NoProfile -ExecutionPolicy Bypass -File C:\speckle\Get-BundleProperties.ps1 -ProjectId PROJECT_ID -ModelId MODEL_ID -VersionId VERSION_ID -OutFile C:\speckle\properties.csv -DuckDb C:\speckle\duckdb.exe
```

If the script fails, **Run DOS command** puts the reason in `CommandErrorOutput` and a non-zero
`CommandExitCode`; check them before reading the file. End `-OutFile` in `.json` instead to get the
same JSON rows as the function returns.

## Troubleshooting

| What you see | What it means |
| - | - |
| `401` or `403` | The function's token is missing, expired, or lacks access to that project. Check `SPECKLE_TOKEN`. |
| `404` from the function | The version is in the earlier format, not a bundle. For those versions, call the [properties export](https://docs.speckle.systems/developers/api/rest.md#properties-export) directly, as before. |
| `Version has no .eav.type_eav.parquet file` | The version's bundle is incomplete. Republish the model and try the new version. |
| Slow, or your flow runs out of memory | The function returns every property of every element. Narrow it: add a `WHERE` clause to the function's query so only the rows you need come back. |


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.